From 7508627dc52046fe078a1df940fb5cf172838801 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 27 Dec 2023 17:19:45 +0100 Subject: [PATCH 01/35] :sparkles: Change defaults for new grid tracks --- common/src/app/common/geom/shapes/grid_layout/params.cljc | 8 ++++---- common/src/app/common/types/shape/layout.cljc | 3 ++- .../workspace/sidebar/options/menus/layout_container.cljs | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/common/src/app/common/geom/shapes/grid_layout/params.cljc b/common/src/app/common/geom/shapes/grid_layout/params.cljc index b50fbf4483..7c0dafc4ed 100644 --- a/common/src/app/common/geom/shapes/grid_layout/params.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/params.cljc @@ -113,8 +113,8 @@ ([_objects shapes parent] (if (empty? shapes) - (-> {:layout-grid-columns [{:type :auto} {:type :auto}] - :layout-grid-rows [{:type :auto} {:type :auto}]} + (-> {:layout-grid-columns [ctl/default-track-value ctl/default-track-value] + :layout-grid-rows [ctl/default-track-value ctl/default-track-value]} (ctl/create-cells [1 1 2 2])) (let [all-shapes-rect (gco/shapes->rect shapes) @@ -149,8 +149,8 @@ 0 (/ (- (:height all-shapes-rect) total-rows-height) (dec num-rows))) - layout-grid-rows (mapv (constantly (array-map :type :auto)) rows) - layout-grid-columns (mapv (constantly (array-map :type :auto)) cols) + layout-grid-rows (mapv (constantly ctl/default-track-value) rows) + layout-grid-columns (mapv (constantly ctl/default-track-value) cols) parent-childs-vector (gpt/to-vec (gpo/origin (:points parent)) (gpt/point all-shapes-rect)) p-left (:x parent-childs-vector) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 30a866b76a..0745a4f9e3 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -590,7 +590,8 @@ (declare assign-cells) (def default-track-value - {:type :auto}) + {:type :flex + :value 1}) (def grid-cell-defaults {:row-span 1 diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 8138f0a3e4..dc97af314b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -966,7 +966,7 @@ (mf/use-fn (mf/deps type reorder-track index) (fn [drop-position data event] - (reorder-track type (:index data) (if (= :top drop-position) (dec index) index) (kbd/mod? event)))) + (reorder-track type (:index data) (if (= :top drop-position) (dec index) index) (not (kbd/mod? event))))) pointer-enter (mf/use-fn From da358d635b6580ce21acf359272abbd20cac51ca Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 27 Dec 2023 17:22:57 +0100 Subject: [PATCH 02/35] :sparkles: Reorder tracks from grid editor --- common/src/app/common/geom/line.cljc | 18 ++ .../geom/shapes/grid_layout/positions.cljc | 19 +- common/src/app/common/types/shape/layout.cljc | 14 + .../viewport/grid_layout_editor.cljs | 296 +++++++++++++----- .../viewport/grid_layout_editor.scss | 13 +- 5 files changed, 266 insertions(+), 94 deletions(-) create mode 100644 common/src/app/common/geom/line.cljc diff --git a/common/src/app/common/geom/line.cljc b/common/src/app/common/geom/line.cljc new file mode 100644 index 0000000000..6ab28d5fc1 --- /dev/null +++ b/common/src/app/common/geom/line.cljc @@ -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)) diff --git a/common/src/app/common/geom/shapes/grid_layout/positions.cljc b/common/src/app/common/geom/shapes/grid_layout/positions.cljc index e6504519f5..6ab0c0bb75 100644 --- a/common/src/app/common/geom/shapes/grid_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/positions.cljc @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] + [app.common.geom.line :as gl] [app.common.geom.point :as gpt] [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.grid-layout.layout-data :as ld] @@ -182,18 +183,6 @@ (-> (ctm/add-modifiers fill-modifiers) (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 [{:keys [layout-bounds row-tracks column-tracks]} position] @@ -206,7 +195,7 @@ (fn is-inside-track? [{:keys [start-p size] :as track}] (let [unit-v (vfn 1) 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 (fn [type] @@ -214,8 +203,8 @@ (fn [[selected selected-dist] [cur-idx {:keys [start-p size] :as track}]] (let [unit-v (vfn 1) end-p (gpt/add start-p (ofn size)) - dist-1 (mth/abs (line-value [start-p unit-v] position)) - dist-2 (mth/abs (line-value [end-p unit-v] position))] + dist-1 (mth/abs (gl/line-value [start-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)) [[cur-idx track] (min dist-1 dist-2)] diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 0745a4f9e3..58ccb6a0a3 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -327,6 +327,20 @@ [pad-top pad-right pad-top pad-right] [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 [child] (if (and (fill-width? child) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 8066696b00..ddac9377a5 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] + [app.common.geom.line :as gl] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] @@ -163,7 +164,7 @@ (mf/set-ref-val! dragging-ref true) (mf/set-ref-val! start-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 (mf/use-callback @@ -174,7 +175,7 @@ (dom/release-pointer event) (mf/set-ref-val! dragging-ref false) (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 (mf/use-callback @@ -185,8 +186,8 @@ pos (dom/get-client-position event) pt (uwvv/point->viewport pos)] (mf/set-ref-val! current-pos-ref pos) - (when on-drag-delta (on-drag-delta (gpt/to-vec start pos))) - (when on-drag-position (on-drag-position pt))))))] + (when on-drag-delta (on-drag-delta event (gpt/to-vec start pos))) + (when on-drag-position (on-drag-position event pt))))))] {:handle-pointer-down handle-pointer-down :handle-lost-pointer-capture handle-lost-pointer-capture @@ -212,7 +213,7 @@ handle-drag-position (mf/use-callback (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) [new-row new-column new-row-span new-column-span] @@ -410,7 +411,7 @@ handle-drag-position (mf/use-callback (mf/deps shape track-before track-after) - (fn [position] + (fn [_ position] (let [[tracks-prop axis] (if (= :column type) [:layout-grid-columns :x] [:layout-grid-rows :y]) @@ -451,11 +452,14 @@ (let [shape (unchecked-get props "shape") index (unchecked-get props "index") last? (unchecked-get props "last?") + drop? (unchecked-get props "drop?") track-before (unchecked-get props "track-before") track-after (unchecked-get props "track-after") 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") type (unchecked-get props "type") zoom (unchecked-get props "zoom") @@ -477,7 +481,7 @@ [(+ column-total-size column-total-gap) (max 0 (- layout-gap-row (/ 10 zoom)) (/ 8 zoom))]) - start-p + start-p-resize (cond-> start-p (and (= type :column) (= index 0)) (gpt/subtract (hv (/ width 2))) @@ -491,22 +495,52 @@ (and (= type :row) (not= index 0) (not last?)) (-> (gpt/subtract (vv (/ layout-gap-row 2))) - (gpt/subtract (vv (/ height 2)))))] + (gpt/subtract (vv (/ height 2))))) - [:rect.resize-track-handler - {:x (:x start-p) - :y (:y start-p) - :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}}])) + start-p-drop + (cond-> start-p + (and (= type :column) (= index 0)) + (gpt/subtract (hv (/ width 2))) + + (and (= type :row) (= index 0)) + (gpt/subtract (vv (/ height 2))) + + (and (= type :column) last?) + (gpt/add (hv (/ width 2))) + + (and (= type :row) last?) + (gpt/add (vv (/ height 2))) + + (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-h1 20) @@ -620,7 +654,7 @@ (dm/str value)]])) (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} [props] (let [shape (unchecked-get props "shape") @@ -631,6 +665,11 @@ track-data (unchecked-get props "track-data") layout-data (unchecked-get props "layout-data") 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) [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) (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) medium? (and (>= trackwidth small-size-limit) (< trackwidth medium-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/deps track-data) (fn [] (dom/set-value! (mf/ref-val track-input-ref) (format-size track-data)))) + [:g.track [:g {:on-pointer-enter handle-pointer-enter :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 (gmt/rotate (:transform shape) -90))))} - (when (and hovering? (not small?)) - [:rect {:x (+ text-x (/ 18 zoom)) - :y text-y - :width (- text-width (/ 36 zoom)) - :height (- text-height (/ 5 zoom)) - :rx (/ 3 zoom) - :fill "var(--grid-editor-marker-color)" - :opacity 0.2}]) + [:rect {:class (stl/css :grid-editor-header-hover) + :x (+ text-x (/ 18 zoom)) + :y text-y + :width (- text-width (/ 36 zoom)) + :height (- text-height (/ 5 zoom)) + :rx (/ 3 zoom) + :style {:cursor "pointer"} + :opacity (if (and hovering? (not small?)) 0.2 0)}] (when (not small?) [: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 {:ref track-input-ref :style {} @@ -778,6 +844,7 @@ :layout-data layout-data :shape shape :snap-pixel? snap-pixel? + :drop? drop? :start-p start-p :track-after track-data :track-before track-before @@ -855,8 +922,8 @@ (mf/deps shape children) #(gsg/calc-layout-data shape bounds children all-bounds objects)) - width (max (gpo/width-points bounds) (+ column-total-size column-total-gap)) - height (max (gpo/height-points bounds) (+ row-total-size row-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 (ctl/v-padding shape))) handle-pointer-down (mf/use-callback @@ -875,7 +942,68 @@ (mf/use-callback (mf/deps (:id shape)) (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 (fn [] @@ -914,15 +1042,21 @@ :on-click handle-add-row}]]) (for [[idx column-data] (d/enumerate column-tracks)] - [:& track {:key (dm/str "column-track-" idx) - :shape shape - :zoom zoom - :type :column - :index idx - :layout-data layout-data - :snap-pixel? snap-pixel? - :track-data column-data - :hovering? (contains? hover-columns idx)}]) + (let [drop? (and (= :column @drop-track-type*) + (= idx @drop-track-target*))] + [:& track {:key (dm/str "column-track-" idx) + :shape shape + :zoom zoom + :type :column + :index idx + :layout-data layout-data + :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 (when-not (empty? column-tracks) @@ -940,27 +1074,36 @@ :type :column :value (dm/str (inc (count column-tracks))) :zoom zoom}] - [:& resize-track-handler - {:index (count column-tracks) - :last? true - :shape shape - :layout-data layout-data - :snap-pixel? snap-pixel? - :start-p end-p - :type :column - :track-before (last column-tracks) - :zoom zoom}]])) + (let [drop? (and (= :column @drop-track-type*) + (= (count column-tracks) @drop-track-target*))] + [:& resize-track-handler + {:index (count column-tracks) + :last? true + :drop? drop? + :shape shape + :layout-data layout-data + :snap-pixel? snap-pixel? + :start-p end-p + :type :column + :track-before (last column-tracks) + :zoom zoom}])])) (for [[idx row-data] (d/enumerate row-tracks)] - [:& track {:index idx - :key (dm/str "row-track-" idx) - :layout-data layout-data - :shape shape - :snap-pixel? snap-pixel? - :track-data row-data - :type :row - :zoom zoom - :hovering? (contains? hover-rows idx)}]) + (let [drop? (and (= :row @drop-track-type*) + (= idx @drop-track-target*))] + [:& track {:index idx + :key (dm/str "row-track-" idx) + :layout-data layout-data + :shape shape + :snap-pixel? snap-pixel? + :drop? drop? + :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) (let [last-track (last row-tracks) start-p (:start-p last-track) @@ -977,13 +1120,16 @@ :type :row :value (dm/str (inc (count row-tracks))) :zoom zoom}]] - [:& resize-track-handler - {:index (count row-tracks) - :last? true - :shape shape - :layout-data layout-data - :start-p end-p - :type :row - :track-before (last row-tracks) - :snap-pixel? snap-pixel? - :zoom zoom}]]))])]))) + (let [drop? (and (= :row @drop-track-type*) + (= (count row-tracks) @drop-track-target*))] + [:& resize-track-handler + {:index (count row-tracks) + :last? true + :drop? drop? + :shape shape + :layout-data layout-data + :start-p end-p + :type :row + :track-before (last row-tracks) + :snap-pixel? snap-pixel? + :zoom zoom}])]))])]))) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss index c519a0356d..497bc2e879 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss @@ -18,30 +18,35 @@ } .grid-editor-wrapper { + cursor: grab; width: 100%; height: 80%; display: flex; + flex-direction: column; justify-content: center; align-items: center; } +.grid-editor-header-hover { + fill: var(--grid-editor-marker-color); +} + .grid-editor-label { + flex: 1; background: none; - border-bottom: calc($s-1 / var(--zoom)) solid transparent; border: 0; color: var(--grid-editor-marker-text); font-family: worksans; font-size: calc($fs-12 / var(--zoom)); font-weight: 400; margin: 0; - max-width: calc($s-80 / var(--zoom)); + max-width: calc($s-60 / var(--zoom)); padding: 0; - padding: $s-4; + padding: calc($s-4 / var(--zoom)); text-align: center; &:focus { outline: none; - border-bottom: calc($s-1 / var(--zoom)) solid var(--grid-editor-marker-text); } } From 9ed3ad2f3c7bc64052c8c82037f6f79799b4a66d Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 29 Dec 2023 15:55:59 +0100 Subject: [PATCH 03/35] :sparkles: Right click options on grid editor --- common/src/app/common/data.cljc | 7 + common/src/app/common/types/shape/layout.cljc | 310 +++++++++++++----- frontend/src/app/main/data/workspace.cljs | 23 ++ .../app/main/data/workspace/shape_layout.cljs | 89 ++++- .../app/main/ui/workspace/context_menu.cljs | 61 ++++ .../viewport/grid_layout_editor.cljs | 44 ++- 6 files changed, 422 insertions(+), 112 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index c997c05c0f..4068839865 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -517,6 +517,13 @@ (->> (apply c/iteration args) (concat-all))) +(defn add-at-index + "Insert an element in a vector at an arbitrary index" + [coll index element] + (assert (vector? coll)) + (let [[before after] (split-at index coll)] + (concat-vec [] before [element] after))) + (defn insert-at-index "Insert a list of elements at the given index of a previous list. Replace all existing elems." diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 58ccb6a0a3..c6aa7cb55b 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -329,14 +329,14 @@ (defn h-padding [{:keys [layout-padding-type layout-padding]}] - (let [{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding] + (let [{pad-right :p2 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] + (let [{pad-top :p1 pad-bottom :p3} layout-padding] (if (= :simple layout-padding-type) (+ pad-top pad-top) (+ pad-top pad-bottom)))) @@ -615,53 +615,201 @@ :justify-self :auto :shapes []}) +(declare resize-cell-area) +(declare cells-by-column) +(declare cells-by-row) + +(defn remove-cell-areas + "Remove the areas in the given `index` before and after the index" + [parent prop index] + (let [prop-span (if (= prop :column) :row-span :column-span) + cells (if (= prop :column) (cells-by-column parent index) (cells-by-row parent index))] + (->> cells + (filter #(> (get % prop-span) 1)) + (reduce + (fn [parent cell] + (let [changed-cells + (cond + ;; New track at the beginning + (= (get cell prop) (inc index)) + [(assoc cell prop-span 1) + (assoc cell :id (uuid/next) :shapes [] prop (inc (get cell prop)) prop-span (dec (get cell prop-span)))] + + ;; New track at the middle + (< (get cell prop) (inc index) (+ (get cell prop) (dec (get cell prop-span)))) + [(assoc cell prop-span (- (inc index) (get cell prop))) + (assoc cell :id (uuid/next) :shapes [] prop (inc index) prop-span 1) + (assoc cell :id (uuid/next) :shapes [] prop (+ index 2) prop-span (- (+ (get cell prop) (dec (get cell prop-span))) (inc index)))] + + ;; New track at the end + (= (+ (get cell prop) (dec (get cell prop-span))) (inc index)) + [(assoc cell prop-span (- (inc index) (get cell prop))) + (assoc cell :id (uuid/next) :shapes [] prop (inc index) prop-span 1)])] + + (->> changed-cells + (reduce #(update %1 :layout-grid-cells assoc (:id %2) %2) parent)))) + parent)))) + +(defn remove-cell-areas-after + "Remove the areas in the given `index` but only after the index." + [parent prop index] + (let [prop-span (if (= prop :column) :column-span :row-span) + cells (if (= type :column) (cells-by-column parent index) (cells-by-row parent index))] + (->> cells + (filter #(> (get % prop-span) 1)) + (reduce + (fn [parent cell] + (let [changed-cells + (cond + ;; New track at the beginning + (= (get cell prop) (inc index)) + [(assoc cell prop-span 1) + (assoc cell :id (uuid/next) :shapes [] prop (inc (get cell prop)) prop-span (dec (get cell prop-span)))] + + ;; New track at the middle + (< (get cell prop) (inc index) (+ (get cell prop) (dec (get cell prop-span)))) + [(assoc cell prop-span (- (+ index 2) (get cell prop))) + (assoc cell :id (uuid/next) :shapes [] prop (+ index 2) prop-span (- (+ (get cell prop) (dec (get cell prop-span))) (inc index)))])] + (->> changed-cells + (reduce #(update %1 :layout-grid-cells assoc (:id %2) %2) parent)))) + parent)))) + ;; Adding a track creates the cells. We should check the shapes that are not tracked (with default values) and assign to the correct tracked values + +(defn add-grid-track + ([type parent value] + (add-grid-track type parent value nil)) + ([type parent value index] + (dm/assert! + "expected a valid grid definition for `value`" + (check-grid-track! value)) + + (let [[tracks-prop tracks-prop-other prop prop-other prop-span prop-span-other] + (if (= type :column) + [:layout-grid-columns :layout-grid-rows :column :row :column-span :row-span] + [:layout-grid-rows :layout-grid-columns :row :column :row-span :column-span]) + + new-index (d/nilv index (count (get parent tracks-prop))) + new-track-num (inc new-index) + + ;; Increase the values for the existing cells + layout-grid-cells + (-> (:layout-grid-cells parent) + (update-vals + (fn [cell] + (cond-> cell + (>= (get cell prop) new-track-num) + (update prop inc) + + (and (< (get cell prop) new-track-num) + (> (get cell prop-span) 1) + (>= (+ (get cell prop) (dec (get cell prop-span))) new-track-num)) + (update prop-span inc))))) + + ;; Search for the cells already created + exist-cells? + (into #{} + (comp (filter + (fn [cell] + (and (>= new-track-num (get cell prop)) + (< new-track-num (+ (get cell prop) (get cell prop-span)))))) + (mapcat #(range (get % prop-other) (+ (get % prop-other) (get % prop-span-other))))) + (vals layout-grid-cells)) + + ;; Create the new cells as necesary + layout-grid-cells + (->> (d/enumerate (get parent tracks-prop-other)) + (remove (fn [[idx _]] (exist-cells? (inc idx)))) + (reduce + (fn [result [idx _]] + (let [id (uuid/next)] + (assoc result id + (merge {:id id + prop-other (inc idx) + prop new-track-num} + grid-cell-defaults)))) + layout-grid-cells))] + + (-> parent + (update tracks-prop d/add-at-index new-index value) + (assoc :layout-grid-cells layout-grid-cells))))) + (defn add-grid-column - [parent value] - (dm/assert! - "expected a valid grid definition for `value`" - (check-grid-track! value)) - - (let [rows (:layout-grid-rows parent) - new-col-num (inc (count (:layout-grid-columns parent))) - - layout-grid-cells - (->> (d/enumerate rows) - (reduce (fn [result [row-idx _]] - (let [id (uuid/next)] - (assoc result id - (merge {:id id - :row (inc row-idx) - :column new-col-num} - grid-cell-defaults)))) - (:layout-grid-cells parent)))] - (-> parent - (update :layout-grid-columns (fnil conj []) value) - (assoc :layout-grid-cells layout-grid-cells)))) + ([parent value] + (add-grid-column parent value nil)) + ([parent value index] + (add-grid-track :column parent value index))) (defn add-grid-row - [parent value] - (dm/assert! - "expected a valid grid definition for `value`" - (check-grid-track! value)) + ([parent value] + (add-grid-row parent value nil)) + ([parent value index] + (add-grid-track :row parent value index))) - (let [cols (:layout-grid-columns parent) - new-row-num (inc (count (:layout-grid-rows parent))) +(defn- duplicate-cells + [shape prop from-index to-index ids-map] - layout-grid-cells - (->> (d/enumerate cols) - (reduce (fn [result [col-idx _]] - (let [id (uuid/next)] - (assoc result id - (merge {:id id - :column (inc col-idx) - :row new-row-num} - grid-cell-defaults)))) - (:layout-grid-cells parent)))] - (-> parent - (update :layout-grid-rows (fnil conj []) value) - (assoc :layout-grid-cells layout-grid-cells)))) + (let [[prop-span prop-other prop-other-span] + (if (= prop :column) + [:column-span :row :row-span] + [:row-span :column :column-span]) + from-cells + (if (= prop :column) + (cells-by-column shape from-index) + (cells-by-row shape from-index)) + + to-cells + (if (= prop :column) + (cells-by-column shape to-index) + (cells-by-row shape to-index)) + + to-cells-idx (d/index-by prop-other to-cells) + + ;; This loop will go throught the original cells and copy their data to the target cell + ;; After this some cells could have no correspondence and should be removed + [shape matched] + (loop [from-cells (seq from-cells) + matched #{} + result shape] + (if-let [cell (first from-cells)] + (let [match-cell + (-> (get to-cells-idx (get cell prop-other)) + (d/patch-object (select-keys cell [prop-other-span :position :align-self :justify-self])) + (cond-> (= (get cell prop-span) 1) + (assoc :shapes (mapv ids-map (:shapes cell)))))] + (recur (rest from-cells) + (conj matched (:id match-cell)) + (assoc-in result [:layout-grid-cells (:id match-cell)] match-cell))) + + [result matched])) + + ;; Remove cells that haven't been matched + shape + (->> to-cells + (remove (fn [{:keys [id]}] (contains? matched id))) + (reduce (fn [shape cell] + (update shape :layout-grid-cells dissoc (:id cell))) + shape))] + + shape)) + + +(defn duplicate-row + [shape index ids-map] + (let [value (dm/get-in shape [:layout-grid-rows index])] + (-> shape + (remove-cell-areas-after :row index) + (add-grid-row value (inc index)) + (duplicate-cells :row index (inc index) ids-map)))) + +(defn duplicate-column + [shape index ids-map] + (let [value (dm/get-in shape [:layout-grid-columns index])] + (-> shape + (remove-cell-areas-after :column index) + (add-grid-column value (inc index)) + (duplicate-cells :column index (inc index) ids-map)))) (defn make-remove-cell [attr span-attr track-num] @@ -762,12 +910,9 @@ update-vals (fn [cell] (update cell prop #(get remap-tracks % %))))))) -(declare resize-cell-area) -(declare cells-by-column) -(declare cells-by-row) (defn- reorder-grid-track - [parent from-index to-index move-content? cells-by tracks-props prop prop-span] + [parent from-index to-index move-content? tracks-props prop] (let [from-track (inc from-index) to-track (if (< to-index from-index) (+ to-index 2) @@ -776,23 +921,10 @@ (and move-content? (not= from-track to-track)) parent - (if move-content? - (->> (concat (cells-by parent (dec from-track)) - (cells-by parent (dec to-track))) - (reduce (fn [parent cell] - (cond-> parent - (and (> (get cell prop-span) 1) - (or (> to-track from-track) (not (= to-track (get cell prop)))) - (or (< to-track from-track) (not (= to-track (+ (get cell prop) (dec (get cell prop-span))))))) - (resize-cell-area - (:row cell) - (:column cell) - (:row cell) - (:column cell) - (if (= prop :row) 1 (:row-span cell)) - (if (= prop :column) 1 (:column-span cell))))) - parent)) - parent) + (cond-> parent + move-content? + (-> (remove-cell-areas prop (dec from-track)) + (remove-cell-areas prop (dec to-track)))) parent (reorder-grid-tracks parent tracks-props from-index to-index)] @@ -803,11 +935,11 @@ (defn reorder-grid-column [parent from-index to-index move-content?] - (reorder-grid-track parent from-index to-index move-content? cells-by-column :layout-grid-columns :column :column-span)) + (reorder-grid-track parent from-index to-index move-content? :layout-grid-columns :column)) (defn reorder-grid-row [parent from-index to-index move-content?] - (reorder-grid-track parent from-index to-index move-content? cells-by-row :layout-grid-rows :row :row-span)) + (reorder-grid-track parent from-index to-index move-content? :layout-grid-rows :row)) (defn cells-seq [{:keys [layout-grid-cells layout-grid-dir]} & {:keys [sort?] :or {sort? false}}] @@ -1239,30 +1371,42 @@ (assoc parent :shapes (into [] (reverse new-shapes))))) (defn cells-by-row - [parent index] - (->> (:layout-grid-cells parent) - (filter (fn [[_ {:keys [row row-span]}]] - (and (>= (inc index) row) - (< (inc index) (+ row row-span))))) - (map second))) + ([parent index] + (cells-by-row parent index true)) + ([parent index check-span?] + (->> (:layout-grid-cells parent) + (filter (fn [[_ {:keys [row row-span]}]] + (if check-span? + (and (>= (inc index) row) + (< (inc index) (+ row row-span))) + (= (inc index) row)))) + (map second)))) (defn cells-by-column - [parent index] - (->> (:layout-grid-cells parent) - (filter (fn [[_ {:keys [column column-span]}]] - (and (>= (inc index) column) - (< (inc index) (+ column column-span))))) - (map second))) + ([parent index] + (cells-by-column parent index true)) + ([parent index check-span?] + (->> (:layout-grid-cells parent) + (filter (fn [[_ {:keys [column column-span]}]] + (if check-span? + (and (>= (inc index) column) + (< (inc index) (+ column column-span))) + (= (inc index) column)))) + (map second)))) (defn shapes-by-row - [parent index] - (->> (cells-by-row parent index) - (mapcat :shapes))) + ([parent index] + (shapes-by-row parent index true)) + ([parent index check-span?] + (->> (cells-by-row parent index check-span?) + (mapcat :shapes)))) (defn shapes-by-column - [parent index] - (->> (cells-by-column parent index) - (mapcat :shapes))) + ([parent index] + (shapes-by-column parent index true)) + ([parent index check-span?] + (->> (cells-by-column parent index check-span?) + (mapcat :shapes)))) (defn cells-coordinates "Given a group of cells returns the coordinates that define" diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index b711b1ead4..0eee768b7b 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1490,6 +1490,27 @@ (rx/of (show-context-menu (-> params (assoc :kind :page :selected (:id page)))))))) +(defn show-track-context-menu + [{:keys [grid-id type index] :as params}] + (ptk/reify ::show-track-context-menu + ptk/WatchEvent + (watch [_ _ _] + (rx/of (show-context-menu + (-> params (assoc :kind :grid-track + :grid-id grid-id + :type type + :index index))))))) + +(defn show-grid-cell-context-menu + [{:keys [grid-id] :as params}] + (ptk/reify ::show-grid-cell-context-menu + ptk/WatchEvent + (watch [_ state _] + (let [cells (get-in state [:workspace-grid-edition grid-id :selected])] + (rx/of (show-context-menu + (-> params (assoc :kind :grid-cells + :grid-id grid-id + :cells cells)))))))) (def hide-context-menu (ptk/reify ::hide-context-menu ptk/UpdateEvent @@ -1497,6 +1518,8 @@ (assoc-in state [:workspace-local :context-menu] nil)))) + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Clipboard ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index e89f415ea7..98624d1286 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -9,7 +9,9 @@ [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.files.changes-builder :as pcb] [app.common.files.helpers :as cfh] + [app.common.geom.point :as gpt] [app.common.geom.shapes.flex-layout :as flex] [app.common.geom.shapes.grid-layout :as grid] [app.common.types.component :as ctc] @@ -247,27 +249,29 @@ (dwu/commit-undo-transaction undo-id)))))) (defn add-layout-track - [ids type value] - (assert (#{:row :column} type)) - (ptk/reify ::add-layout-column - ptk/WatchEvent - (watch [_ _ _] - (let [undo-id (js/Symbol)] - (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes - ids - (fn [shape] - (case type - :row (ctl/add-grid-row shape value) - :column (ctl/add-grid-column shape value)))) - (ptk/data-event :layout/update ids) - (dwu/commit-undo-transaction undo-id)))))) + ([ids type value] + (add-layout-track ids type value nil)) + ([ids type value index] + (assert (#{:row :column} type)) + (ptk/reify ::add-layout-track + ptk/WatchEvent + (watch [_ _ _] + (let [undo-id (js/Symbol)] + (rx/of (dwu/start-undo-transaction undo-id) + (dwc/update-shapes + ids + (fn [shape] + (case type + :row (ctl/add-grid-row shape value index) + :column (ctl/add-grid-column shape value index)))) + (ptk/data-event :layout/update ids) + (dwu/commit-undo-transaction undo-id))))))) (defn remove-layout-track [ids type index] (assert (#{:row :column} type)) - (ptk/reify ::remove-layout-column + (ptk/reify ::remove-layout-track ptk/WatchEvent (watch [_ _ _] (let [undo-id (js/Symbol)] @@ -281,6 +285,59 @@ (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) +(defn duplicate-layout-track + [ids type index] + (assert (#{:row :column} type)) + + (ptk/reify ::duplicate-layout-track + ptk/WatchEvent + (watch [it state _] + (let [file-id (:current-file-id state) + page (wsh/lookup-page state) + objects (:objects page) + libraries (wsh/get-libraries state) + library-data (wsh/get-file state file-id) + shape-id (first ids) + base-shape (get objects shape-id) + + shapes-by-track + (if (= type :column) + (ctl/shapes-by-column base-shape index false) + (ctl/shapes-by-row base-shape index false)) + + ;; Change to set in order to use auxiliary functions + selected (set shapes-by-track) + + changes + (->> (dwse/prepare-duplicate-changes objects page selected (gpt/point 0 0) it libraries library-data file-id) + (dwse/duplicate-changes-update-indices objects selected)) + + ;; Creates a map with shape-id => duplicated-shape-id + ids-map + (->> changes + :redo-changes + (filter #(= (:type %) :add-obj)) + (filter #(selected (:old-id %))) + (map #(vector (:old-id %) (get-in % [:obj :id]))) + (into {})) + + changes + (-> changes + (pcb/update-shapes + ids + (fn [shape] + ;; The duplication could have altered the grid so we restore the values, we'll calculate the good ones now + (let [shape (merge shape (select-keys base-shape [:layout-grid-cells :layout-grid-columns :layout-grid-rows]))] + (case type + :row (ctl/duplicate-row shape index ids-map) + :column (ctl/duplicate-column shape index ids-map)))))) + + undo-id (js/Symbol)] + (rx/of (dwu/start-undo-transaction undo-id) + (dwc/commit-changes changes) + (ptk/data-event :layout/update ids) + (dwu/commit-undo-transaction undo-id)))))) + (defn reorder-layout-track [ids type from-index to-index move-content?] (assert (#{:row :column} type)) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index b028ad0014..7107b5a47f 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -14,6 +14,7 @@ [app.common.types.component :as ctk] [app.common.types.container :as ctn] [app.common.types.page :as ctp] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.events :as ev] [app.main.data.modal :as modal] @@ -549,6 +550,64 @@ :shortcut (sc/get-tooltip :toggle-focus-mode) :on-click do-toggle-focus-mode}])])) +(mf/defc grid-track-context-menu + [{:keys [mdata] :as props}] + (let [{:keys [type index grid-id]} mdata + do-delete-track + (mf/use-callback + (mf/deps grid-id type index) + (fn [] + (st/emit! (dwsl/remove-layout-track [grid-id] type index)))) + + do-add-track-before + (mf/use-callback + (mf/deps grid-id type index) + (fn [] + (st/emit! (dwsl/add-layout-track [grid-id] type ctl/default-track-value index)))) + + do-add-track-after + (mf/use-callback + (mf/deps grid-id type index) + (fn [] + (st/emit! (dwsl/add-layout-track [grid-id] type ctl/default-track-value (inc index))))) + + do-duplicate-track + (mf/use-callback + (mf/deps grid-id type index) + (fn [] + (st/emit! (dwsl/duplicate-layout-track [grid-id] type index))))] + + (if (= type :column) + [:* + [:& menu-entry {:title "Duplicate column" :on-click do-duplicate-track}] + [:& menu-entry {:title "Add 1 column to the left" :on-click do-add-track-before}] + [:& menu-entry {:title "Add 1 column to the right" :on-click do-add-track-after}] + [:& menu-entry {:title "Delete column" :on-click do-delete-track}]] + + [:* + [:& menu-entry {:title "Duplicate row" :on-click do-duplicate-track}] + [:& menu-entry {:title "Add 1 row above" :on-click do-add-track-before}] + [:& menu-entry {:title "Add 1 row bellow" :on-click do-add-track-after}] + [:& menu-entry {:title "Delete row" :on-click do-delete-track}]]))) + +(mf/defc grid-cells-context-menu + [{:keys [mdata] :as props}] + (let [{:keys [grid-id cells]} mdata + + do-merge-cells + (mf/use-callback + (mf/deps grid-id cells) + (fn [])) + + do-create-board + (mf/use-callback + (mf/deps grid-id cells) + (fn []))] + [:* + [:& menu-entry {:title "Merge cells" :on-click do-merge-cells}] + [:& menu-entry {:title "Create board" :on-click do-create-board}]])) + + (mf/defc context-menu [] (let [mdata (mf/deref menu-ref) @@ -583,6 +642,8 @@ (case (:kind mdata) :shape [:& shape-context-menu {:mdata mdata}] :page [:& page-item-context-menu {:mdata mdata}] + :grid-track [:& grid-track-context-menu {:mdata mdata}] + :grid-cells [:& grid-cells-context-menu {:mdata mdata}] [:& viewport-context-menu {:mdata mdata}])]])) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index ddac9377a5..ddc740d96d 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -337,9 +337,18 @@ (mf/use-callback (mf/deps (:id shape) (:id cell) selected?) (fn [event] - (if (and (kbd/shift? event) selected?) - (st/emit! (dwge/remove-selection (:id shape) (:id cell))) - (st/emit! (dwge/select-grid-cell (:id shape) (:id cell) (kbd/shift? event)) ))))] + (when (or (dom/left-mouse? event) (not selected?)) + (if (and (kbd/shift? event) selected?) + (st/emit! (dwge/remove-selection (:id shape) (:id cell))) + (st/emit! (dwge/select-grid-cell (:id shape) (:id cell) (kbd/shift? event))))))) + + handle-context-menu + (mf/use-callback + (fn [event] + (dom/prevent-default event) + (dom/stop-propagation event) + (let [position (dom/get-client-position event)] + (st/emit! (dw/show-grid-cell-context-menu {:position position :grid-id (:id shape)})))))] [:g.cell-editor [:rect @@ -352,6 +361,7 @@ :width cell-width :height cell-height + :on-context-menu handle-context-menu :on-pointer-enter handle-pointer-enter :on-pointer-leave handle-pointer-leave :on-pointer-down handle-pointer-down}] @@ -746,12 +756,6 @@ (fn [] (st/emit! (dwsl/hover-layout-track [(:id shape)] type index false)))) - handle-remove-track - (mf/use-callback - (mf/deps (:id shape) type index) - (fn [] - (st/emit! (dwsl/remove-layout-track [(:id shape)] type index)))) - track-list-prop (if (= type :column) :column-tracks :row-tracks) [text-x text-y text-width text-height] (if (= type :column) @@ -776,6 +780,19 @@ (fn [_ position] (on-move-reorder-track type index position))) + handle-show-track-menu + (mf/use-callback + (fn [event] + (dom/stop-propagation event) + (dom/prevent-default event) + (let [position (cond-> (dom/get-client-position event) + (= type :column) (update :y + 40) + (= type :row) (update :x + 30))] + (st/emit! (dw/show-track-context-menu {:position position + :grid-id (:id shape) + :type type + :index index}))))) + trackwidth (* text-width zoom) medium? (and (>= trackwidth small-size-limit) (< trackwidth medium-size-limit)) small? (< trackwidth small-size-limit) @@ -811,6 +828,7 @@ (when (not small?) [:foreignObject {:x text-x :y text-y :width text-width :height text-height} [:div {:class (stl/css :grid-editor-wrapper) + :on-context-menu handle-show-track-menu :on-pointer-down handle-pointer-down :on-lost-pointer-capture handle-lost-pointer-capture :on-pointer-move handle-pointer-move} @@ -825,7 +843,7 @@ :on-blur handle-blur-track-input}] (when (and hovering? (not medium?) (not small?)) [:button {:class (stl/css :grid-editor-button) - :on-click handle-remove-track} i/delete-refactor])]])] + :on-click handle-show-track-menu} i/menu-refactor])]])] [:g {:transform (when (= type :row) (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p)))} [:& track-marker @@ -952,7 +970,7 @@ handle-start-reorder-track (mf/use-callback (mf/deps layout-data) - (fn [type from-idx] + (fn [type _from-idx] ;; Initialize target-tracks (let [line-vec (if (= type :column) (vv 1) (hv 1)) @@ -979,7 +997,7 @@ handle-move-reorder-track (mf/use-callback - (fn [type from-idx position] + (fn [_type _from-idx position] (let [index (->> (mf/ref-val target-tracks*) (d/seek (fn [[[p1 p2 v] _]] @@ -991,7 +1009,7 @@ handle-end-reorder-track (mf/use-callback (mf/deps base-shape @drop-track-target*) - (fn [type from-index position move-content?] + (fn [type from-index _position move-content?] (when-let [to-index @drop-track-target*] (let [ids [(:id base-shape)]] (cond From 40d4a917e10407b8d2892703af913c9d71940ba4 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 2 Jan 2024 15:31:33 +0100 Subject: [PATCH 04/35] :sparkles: Context menu for cells --- .../src/app/common/files/shapes_helpers.cljc | 140 +++++++++++++----- common/src/app/common/types/shape/layout.cljc | 2 +- frontend/src/app/main/data/workspace.cljs | 7 +- .../app/main/data/workspace/shape_layout.cljs | 87 +++++++++++ .../src/app/main/data/workspace/shapes.cljs | 3 +- .../app/main/ui/workspace/context_menu.cljs | 51 +++++-- .../app/main/ui/workspace/context_menu.scss | 7 + frontend/translations/en.po | 34 +++++ frontend/translations/es.po | 34 +++++ 9 files changed, 305 insertions(+), 60 deletions(-) diff --git a/common/src/app/common/files/shapes_helpers.cljc b/common/src/app/common/files/shapes_helpers.cljc index a36fadf916..04e1d70911 100644 --- a/common/src/app/common/files/shapes_helpers.cljc +++ b/common/src/app/common/files/shapes_helpers.cljc @@ -16,7 +16,7 @@ [app.common.uuid :as uuid])) (defn prepare-add-shape - [changes shape objects _selected] + [changes shape objects] (let [index (:index (meta shape)) id (:id shape) @@ -55,53 +55,115 @@ changes))) (defn prepare-create-artboard-from-selection - [changes id parent-id objects selected index frame-name without-fill?] - (let [selected-objs (map #(get objects %) selected) - new-index (or index - (cfh/get-index-replacement selected objects))] - (when (d/not-empty? selected) - (let [srect (gsh/shapes->rect selected-objs) - selected-id (first selected) + ([changes id parent-id objects selected index frame-name without-fill?] + (prepare-create-artboard-from-selection + changes id parent-id objects selected index frame-name without-fill? nil)) - frame-id (dm/get-in objects [selected-id :frame-id]) - parent-id (or parent-id (dm/get-in objects [selected-id :parent-id])) + ([changes id parent-id objects selected index frame-name without-fill? target-cell-id] + (let [selected-objs (map #(get objects %) selected) + new-index (or index + (cfh/get-index-replacement selected objects))] + (when (d/not-empty? selected) + (let [srect (gsh/shapes->rect selected-objs) + selected-id (first selected) - attrs {:type :frame - :x (:x srect) - :y (:y srect) - :width (:width srect) - :height (:height srect)} + frame-id (dm/get-in objects [selected-id :frame-id]) + parent-id (or parent-id (dm/get-in objects [selected-id :parent-id])) + base-parent (get objects parent-id) - shape (cts/setup-shape - (cond-> attrs - (some? id) - (assoc :id id) + attrs {:type :frame + :x (:x srect) + :y (:y srect) + :width (:width srect) + :height (:height srect)} - (some? frame-name) - (assoc :name frame-name) + shape (cts/setup-shape + (cond-> attrs + (some? id) + (assoc :id id) - :always - (assoc :frame-id frame-id - :parent-id parent-id - :shapes (into [] selected)) + (some? frame-name) + (assoc :name frame-name) - :always - (with-meta {:index new-index}) + :always + (assoc :frame-id frame-id + :parent-id parent-id + :shapes (into [] selected)) - (or (not= frame-id uuid/zero) without-fill?) - (assoc :fills [] :hide-in-viewer true))) + :always + (with-meta {:index new-index}) - [shape changes] - (prepare-add-shape changes shape objects selected) + (or (not= frame-id uuid/zero) without-fill?) + (assoc :fills [] :hide-in-viewer true))) - changes - (prepare-move-shapes-into-frame changes (:id shape) selected objects) + [shape changes] + (prepare-add-shape changes shape objects) - changes - (cond-> changes - (ctl/grid-layout? objects (:parent-id shape)) - (-> (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells) - (pcb/reorder-grid-children [(:parent-id shape)])))] + changes + (prepare-move-shapes-into-frame changes (:id shape) selected objects) - [shape changes])))) + changes + (cond-> changes + (ctl/grid-layout? objects (:parent-id shape)) + (-> (cond-> (some? target-cell-id) + (pcb/update-shapes + [(:parent-id shape)] + (fn [parent] + (-> parent + (assoc :layout-grid-cells (:layout-grid-cells base-parent)) + (assoc-in [:layout-grid-cells target-cell-id :shapes] [id]) + (assoc :position :auto))))) + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells) + (pcb/reorder-grid-children [(:parent-id shape)])))] + [shape changes]))))) + + +(defn prepare-create-empty-artboard + [changes frame-id parent-id objects index frame-name without-fill? target-cell-id] + + (let [base-parent (get objects parent-id) + + attrs {:type :frame + :x 0 + :y 0 + :width 0.01 + :height 0.01} + + shape (cts/setup-shape + (cond-> attrs + (some? frame-id) + (assoc :id frame-id) + + (some? frame-name) + (assoc :name frame-name) + + :always + (assoc :frame-id frame-id + :parent-id parent-id + :shapes []) + + :always + (with-meta {:index index}) + + (or (not= frame-id uuid/zero) without-fill?) + (assoc :fills [] :hide-in-viewer true))) + + [shape changes] + (prepare-add-shape changes shape objects) + + changes + (cond-> changes + (ctl/grid-layout? objects (:parent-id shape)) + (-> (cond-> (some? target-cell-id) + (pcb/update-shapes + [(:parent-id shape)] + (fn [parent] + (-> parent + (assoc :layout-grid-cells (:layout-grid-cells base-parent)) + (assoc-in [:layout-grid-cells target-cell-id :shapes] [frame-id]) + (assoc :position :auto))))) + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells) + (pcb/reorder-grid-children [(:parent-id shape)])))] + + [shape changes])) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index c6aa7cb55b..183d16c8a2 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -1227,6 +1227,7 @@ target-cell (-> prev-cell (assoc + :position :manual :row new-row :column new-column :row-span new-row-span @@ -1459,7 +1460,6 @@ (defn valid-area-cells? [cells] - (let [{:keys [first-row last-row first-column last-column cell-coords]} (cells-coordinates cells)] (every? #(contains? cell-coords %) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 0eee768b7b..055d65e57d 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1506,10 +1506,13 @@ (ptk/reify ::show-grid-cell-context-menu ptk/WatchEvent (watch [_ state _] - (let [cells (get-in state [:workspace-grid-edition grid-id :selected])] + (let [objects (wsh/lookup-page-objects state) + grid (get objects grid-id) + cells (->> (get-in state [:workspace-grid-edition grid-id :selected]) + (map #(get-in grid [:layout-grid-cells %])))] (rx/of (show-context-menu (-> params (assoc :kind :grid-cells - :grid-id grid-id + :grid grid :cells cells)))))))) (def hide-context-menu (ptk/reify ::hide-context-menu diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 98624d1286..dbb65351ec 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -11,6 +11,7 @@ [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] [app.common.files.helpers :as cfh] + [app.common.files.shapes-helpers :as cfsh] [app.common.geom.point :as gpt] [app.common.geom.shapes.flex-layout :as flex] [app.common.geom.shapes.grid-layout :as grid] @@ -583,6 +584,37 @@ (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) +(defn merge-cells + [layout-id ids] + + (ptk/reify ::merge-cells + ptk/WatchEvent + (watch [_ _ _] + (let [undo-id (js/Symbol)] + (rx/of + (dwu/start-undo-transaction undo-id) + (dwc/update-shapes + [layout-id] + (fn [shape objects] + (let [cells (->> ids (map #(get-in shape [:layout-grid-cells %]))) + + {:keys [first-row first-column last-row last-column]} + (ctl/cells-coordinates cells) + + target-cell + (ctl/get-cell-by-position shape first-row first-column)] + (-> shape + (ctl/resize-cell-area + (:row target-cell) (:column target-cell) + first-row + first-column + (inc (- last-row first-row)) + (inc (- last-column first-column))) + (ctl/assign-cells objects))))) + (dwge/clean-selection layout-id) + (ptk/data-event :layout/update [layout-id]) + (dwu/commit-undo-transaction undo-id)))))) + (defn update-grid-cell-position [layout-id cell-id props] @@ -607,3 +639,58 @@ (ctl/assign-cells objects))))) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) + + +(defn create-cell-board + [layout-id cell-ids] + (ptk/reify ::create-cell-board + ptk/WatchEvent + (watch [it state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state) + frame-id (uuid/next) + + undo-id (js/Symbol) + + shape (get objects layout-id) + cells (->> cell-ids (map #(get-in shape [:layout-grid-cells %]))) + selected (into #{} (mapcat :shapes) cells) + + {:keys [first-row first-column last-row last-column]} (ctl/cells-coordinates cells) + + target-cell (ctl/get-cell-by-position shape first-row first-column) + + [_ changes] + (-> (pcb/empty-changes it page-id) + (pcb/with-objects objects) + (cond-> (d/not-empty? selected) + (cfsh/prepare-create-artboard-from-selection + frame-id layout-id objects selected 0 nil true (:id target-cell))) + + (cond-> (empty? (seq selected)) + (cfsh/prepare-create-empty-artboard + frame-id layout-id objects 0 nil true (:id target-cell)))) + + changes + (-> changes + (pcb/update-shapes + [frame-id] + (fn [shape] + (-> shape + (assoc :layout-item-h-sizing :fill) + (assoc :layout-item-v-sizing :fill)))) + (pcb/update-shapes + [layout-id] + (fn [shape] + (let [new-row-span (inc (- last-row first-row)) + new-col-span (inc (- last-column first-column))] + (-> shape + (ctl/resize-cell-area + (:row target-cell) (:column target-cell) + first-row first-column new-row-span new-col-span))))))] + + (rx/of + (dwu/start-undo-transaction undo-id) + (dwc/commit-changes changes) + (ptk/data-event :layout/update [layout-id]) + (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 42422fa521..9a95a69791 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -41,12 +41,11 @@ (watch [it state _] (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - selected (wsh/lookup-selected state) [shape changes] (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) - (cfsh/prepare-add-shape shape objects selected)) + (cfsh/prepare-add-shape shape objects)) changes (cond-> changes (cfh/text-shape? shape) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 7107b5a47f..3312782eac 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -49,7 +49,7 @@ (dom/stop-propagation event)) (mf/defc menu-entry - [{:keys [title shortcut on-click on-pointer-enter on-pointer-leave on-unmount children selected? icon] :as props}] + [{:keys [title shortcut on-click on-pointer-enter on-pointer-leave on-unmount children selected? icon disabled] :as props}] (let [submenu-ref (mf/use-ref nil) hovering? (mf/use-ref false) new-css-system (mf/use-ctx ctx/new-css-system) @@ -89,6 +89,7 @@ [:li {:class (if new-css-system (dom/classnames (css :icon-menu-item) true) (dom/classnames :icon-menu-item true)) + :disabled disabled :ref set-dom-node :on-click on-click :on-pointer-enter on-pointer-enter @@ -113,6 +114,7 @@ (dom/classnames (css :title) true) (dom/classnames :title true))} title]] [:li {:class (dom/classnames (css :context-menu-item) new-css-system) + :disabled disabled :ref set-dom-node :on-click on-click :on-pointer-enter on-pointer-enter @@ -579,33 +581,50 @@ (if (= type :column) [:* - [:& menu-entry {:title "Duplicate column" :on-click do-duplicate-track}] - [:& menu-entry {:title "Add 1 column to the left" :on-click do-add-track-before}] - [:& menu-entry {:title "Add 1 column to the right" :on-click do-add-track-after}] - [:& menu-entry {:title "Delete column" :on-click do-delete-track}]] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.duplicate") :on-click do-duplicate-track}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-before") :on-click do-add-track-before}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-after") :on-click do-add-track-after}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.delete") :on-click do-delete-track}]] [:* - [:& menu-entry {:title "Duplicate row" :on-click do-duplicate-track}] - [:& menu-entry {:title "Add 1 row above" :on-click do-add-track-before}] - [:& menu-entry {:title "Add 1 row bellow" :on-click do-add-track-after}] - [:& menu-entry {:title "Delete row" :on-click do-delete-track}]]))) + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.duplicate") :on-click do-duplicate-track}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-before") :on-click do-add-track-before}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-after") :on-click do-add-track-after}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.delete") :on-click do-delete-track}]]))) (mf/defc grid-cells-context-menu [{:keys [mdata] :as props}] - (let [{:keys [grid-id cells]} mdata + (let [{:keys [grid cells]} mdata + + single? (= (count cells) 1) + can-merge? + (mf/use-memo + (mf/deps cells) + #(ctl/valid-area-cells? cells)) do-merge-cells (mf/use-callback - (mf/deps grid-id cells) - (fn [])) + (mf/deps grid cells) + (fn [] + (st/emit! (dwsl/merge-cells (:id grid) (map :id cells))))) do-create-board (mf/use-callback - (mf/deps grid-id cells) - (fn []))] + (mf/deps grid cells) + (fn [] + (st/emit! (dwsl/create-cell-board (:id grid) (map :id cells)))))] [:* - [:& menu-entry {:title "Merge cells" :on-click do-merge-cells}] - [:& menu-entry {:title "Create board" :on-click do-create-board}]])) + (when (not single?) + [:& menu-entry {:title (tr "workspace.context-menu.grid-cells.merge") + :on-click do-merge-cells + :disabled (not can-merge?)}]) + + (when single? + [:& menu-entry {:title (tr "workspace.context-menu.grid-cells.area") + :on-click do-merge-cells}]) + + [:& menu-entry {:title (tr "workspace.context-menu.grid-cells.create-board") + :on-click do-create-board}]])) (mf/defc context-menu diff --git a/frontend/src/app/main/ui/workspace/context_menu.scss b/frontend/src/app/main/ui/workspace/context_menu.scss index 94f73018ef..f8f8573a13 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.scss +++ b/frontend/src/app/main/ui/workspace/context_menu.scss @@ -110,3 +110,10 @@ } } } + +.icon-menu-item[disabled], +.context-menu-item[disabled] +{ + pointer-events: none; + opacity: 0.6; +} diff --git a/frontend/translations/en.po b/frontend/translations/en.po index f1206c084c..3d32f6632e 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5057,3 +5057,37 @@ msgstr "Choose image" msgid "workspace.options.guides.title" msgstr "Guides" + +msgid "workspace.context-menu.grid-track.column.duplicate" +msgstr "Duplicate column" + +msgid "workspace.context-menu.grid-track.column.add-before" +msgstr "Add 1 column to the left" + +msgid "workspace.context-menu.grid-track.column.add-after" +msgstr "Add 1 column to the right" + +msgid "workspace.context-menu.grid-track.column.delete" +msgstr "Delete column" + +msgid "workspace.context-menu.grid-track.row.duplicate" +msgstr "Duplicate row" + +msgid "workspace.context-menu.grid-track.row.add-before" +msgstr "Add 1 row above" + +msgid "workspace.context-menu.grid-track.row.add-after" +msgstr "Add 1 row bellow" + +msgid "workspace.context-menu.grid-track.row.delete" +msgstr "Delete row" + +msgid "workspace.context-menu.grid-cells.merge" +msgstr "Merge cells" + +msgid "workspace.context-menu.grid-cells.area" +msgstr "Create area" + +msgid "workspace.context-menu.grid-cells.create-board" +msgstr "Create board" + diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 7b4e5b85ed..9fcdbdbcf0 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5146,3 +5146,37 @@ msgstr "Elegir imagen" msgid "workspace.options.guides.title" msgstr "Guías" + +msgid "workspace.context-menu.grid-track.column.duplicate" +msgstr "Duplicar columna" + +msgid "workspace.context-menu.grid-track.column.add-before" +msgstr "Añadir 1 columna a la izquierda" + +msgid "workspace.context-menu.grid-track.column.add-after" +msgstr "Añadir 1 columna a la derecha" + +msgid "workspace.context-menu.grid-track.column.delete" +msgstr "Borrar columna" + +msgid "workspace.context-menu.grid-track.row.duplicate" +msgstr "Duplicar fila" + +msgid "workspace.context-menu.grid-track.row.add-before" +msgstr "Añadir 1 fila encima" + +msgid "workspace.context-menu.grid-track.row.add-after" +msgstr "Añadir 1 fila debajo" + +msgid "workspace.context-menu.grid-track.row.delete" +msgstr "Borrar fila" + +msgid "workspace.context-menu.grid-cells.merge" +msgstr "Fusionar celdas" + +msgid "workspace.context-menu.grid-cells.area" +msgstr "Crear area" + +msgid "workspace.context-menu.grid-cells.create-board" +msgstr "Crear tablero" + From 48e283812eeea2203465664ad82ce7198558936c Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 2 Jan 2024 17:13:49 +0100 Subject: [PATCH 05/35] :bug: Fix some styles --- frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss | 1 + frontend/src/app/main/ui/workspace/context_menu.scss | 3 +-- .../ui/workspace/sidebar/options/menus/layout_container.scss | 4 +++- frontend/src/app/main/ui/workspace/viewport.cljs | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss index 13bf37facb..874935b245 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss @@ -35,6 +35,7 @@ } .layer-title { @include titleTipography; + color: $df-primary; } } } diff --git a/frontend/src/app/main/ui/workspace/context_menu.scss b/frontend/src/app/main/ui/workspace/context_menu.scss index f8f8573a13..23250aa093 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.scss +++ b/frontend/src/app/main/ui/workspace/context_menu.scss @@ -112,8 +112,7 @@ } .icon-menu-item[disabled], -.context-menu-item[disabled] -{ +.context-menu-item[disabled] { pointer-events: none; opacity: 0.6; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss index 4c66d2c375..1bee7524d6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss @@ -174,6 +174,7 @@ .grid-layout-menu-title { flex: 1; font-size: $fs-11; + color: $df-primary; } .edit-mode-btn { @@ -289,7 +290,7 @@ } .track-name { - color: var(--color-foreground-secondary); + color: $df-primary; } .track-detail { @@ -297,6 +298,7 @@ white-space: nowrap; text-overflow: ellipsis; width: 100%; + color: $df-secondary; } .expand-icon { diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 6933fb1c85..8374386cf4 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -229,7 +229,7 @@ show-rules? (and (contains? layout :rules) (not hide-ui?)) - disabled-guides? (or drawing-tool transform) + disabled-guides? (or drawing-tool transform drawing-path? node-editing?) one-selected-shape? (= (count selected-shapes) 1) From c9200f235e62dd551d946ecca397731a4092bd10 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 2 Jan 2024 17:59:07 +0100 Subject: [PATCH 06/35] :recycle: Changes to update-shape parameters --- .../src/app/common/files/changes_builder.cljc | 12 ++-- .../src/app/common/files/shapes_helpers.cljc | 8 +-- frontend/src/app/main/data/workspace.cljs | 3 +- .../src/app/main/data/workspace/changes.cljs | 9 +-- .../src/app/main/data/workspace/comments.cljs | 4 +- .../src/app/main/data/workspace/groups.cljs | 4 +- .../src/app/main/data/workspace/guides.cljs | 6 +- .../data/workspace/libraries_helpers.cljs | 3 +- .../app/main/data/workspace/selection.cljs | 4 +- .../app/main/data/workspace/shape_layout.cljs | 72 ++++++++++--------- .../app/main/data/workspace/transforms.cljs | 10 ++- frontend/src/debug.cljs | 4 +- 12 files changed, 76 insertions(+), 63 deletions(-) diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index 7efc11c311..6668f91af8 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -358,13 +358,15 @@ (defn changed-attrs "Returns the list of attributes that will change when `update-fn` is applied" - [object objects update-fn {:keys [attrs]}] + [object objects update-fn {:keys [attrs with-objects?]}] (let [changed? (fn [old new attr] (let [old-val (get old attr) new-val (get new attr)] (not= old-val new-val))) - new-obj (update-fn object objects)] + new-obj (if with-objects? + (update-fn object objects) + (update-fn object))] (when-not (= object new-obj) (let [attrs (or attrs (d/concat-set (keys object) (keys new-obj)))] (filter (partial changed? object new-obj) attrs))))) @@ -375,8 +377,8 @@ ([changes ids update-fn] (update-shapes changes ids update-fn nil)) - ([changes ids update-fn {:keys [attrs ignore-geometry? ignore-touched] - :or {ignore-geometry? false ignore-touched false}}] + ([changes ids update-fn {:keys [attrs ignore-geometry? ignore-touched with-objects?] + :or {ignore-geometry? false ignore-touched false with-objects? false}}] (assert-container-id! changes) (assert-objects! changes) (let [page-id (::page-id (meta changes)) @@ -412,7 +414,7 @@ update-shape (fn [changes id] (let [old-obj (get objects id) - new-obj (update-fn old-obj objects)] + new-obj (if with-objects? (update-fn old-obj objects) (update-fn old-obj))] (if (= old-obj new-obj) changes (let [[rops uops] (-> (or attrs (d/concat-set (keys old-obj) (keys new-obj))) diff --git a/common/src/app/common/files/shapes_helpers.cljc b/common/src/app/common/files/shapes_helpers.cljc index 04e1d70911..3a375072f9 100644 --- a/common/src/app/common/files/shapes_helpers.cljc +++ b/common/src/app/common/files/shapes_helpers.cljc @@ -34,7 +34,7 @@ (cond-> (some? cell) (pcb/update-shapes [(:parent-id shape)] #(ctl/push-into-cell % [id] row column))) (cond-> (ctl/grid-layout? objects (:parent-id shape)) - (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)))] + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells {:with-objects? true})))] [shape changes])) (defn prepare-move-shapes-into-frame @@ -50,7 +50,7 @@ (pcb/update-shapes ordered-indexes #(cond-> % (cfh/frame-shape? %) (assoc :hide-in-viewer true))) (pcb/change-parent frame-id to-move-shapes 0) (cond-> (ctl/grid-layout? objects frame-id) - (pcb/update-shapes [frame-id] ctl/assign-cells)) + (pcb/update-shapes [frame-id] ctl/assign-cells {:with-objects? true})) (pcb/reorder-grid-children [frame-id])) changes))) @@ -113,7 +113,7 @@ (assoc :layout-grid-cells (:layout-grid-cells base-parent)) (assoc-in [:layout-grid-cells target-cell-id :shapes] [id]) (assoc :position :auto))))) - (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells) + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells {:with-objects? true}) (pcb/reorder-grid-children [(:parent-id shape)])))] [shape changes]))))) @@ -163,7 +163,7 @@ (assoc :layout-grid-cells (:layout-grid-cells base-parent)) (assoc-in [:layout-grid-cells target-cell-id :shapes] [frame-id]) (assoc :position :auto))))) - (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells) + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells {:with-objects? true}) (pcb/reorder-grid-children [(:parent-id shape)])))] [shape changes])) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 055d65e57d..6c72136001 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -855,7 +855,8 @@ (fn [parent objects] (cond-> parent (ctl/grid-layout? parent) - (ctl/assign-cells objects)))) + (ctl/assign-cells objects))) + {:with-objects? true}) (pcb/reorder-grid-children parents) diff --git a/frontend/src/app/main/data/workspace/changes.cljs b/frontend/src/app/main/data/workspace/changes.cljs index 9b7f1c54dc..7a5b55062d 100644 --- a/frontend/src/app/main/data/workspace/changes.cljs +++ b/frontend/src/app/main/data/workspace/changes.cljs @@ -51,8 +51,8 @@ (defn update-shapes ([ids update-fn] (update-shapes ids update-fn nil)) - ([ids update-fn {:keys [reg-objects? save-undo? stack-undo? attrs ignore-tree page-id ignore-remote? ignore-touched undo-group] - :or {reg-objects? false save-undo? true stack-undo? false ignore-remote? false ignore-touched false}}] + ([ids update-fn {:keys [reg-objects? save-undo? stack-undo? attrs ignore-tree page-id ignore-remote? ignore-touched undo-group with-objects?] + :or {reg-objects? false save-undo? true stack-undo? false ignore-remote? false ignore-touched false with-objects? false}}] (dm/assert! "expected a valid coll of uuid's" @@ -70,14 +70,15 @@ update-layout-ids (->> ids (map (d/getf objects)) - (filter #(some update-layout-attr? (pcb/changed-attrs % objects update-fn {:attrs attrs}))) + (filter #(some update-layout-attr? (pcb/changed-attrs % objects update-fn {:attrs attrs :with-objects? with-objects?}))) (map :id)) changes (reduce (fn [changes id] (let [opts {:attrs attrs :ignore-geometry? (get ignore-tree id) - :ignore-touched ignore-touched}] + :ignore-touched ignore-touched + :with-objects? with-objects?}] (pcb/update-shapes changes [id] update-fn (d/without-nils opts)))) (-> (pcb/empty-changes it page-id) (pcb/set-save-undo? save-undo?) diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs index ed0734e707..0c4850a404 100644 --- a/frontend/src/app/main/data/workspace/comments.cljs +++ b/frontend/src/app/main/data/workspace/comments.cljs @@ -13,7 +13,7 @@ [app.common.schema :as sm] [app.common.types.shape-tree :as ctst] [app.main.data.comments :as dcm] - [app.main.data.workspace.changes :as dwc] + [app.main.data.workspace.changes :as dch] [app.main.data.workspace.common :as dwco] [app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.state-helpers :as wsh] @@ -148,7 +148,7 @@ (pcb/update-page-option :comment-threads-position assoc thread-id (select-keys thread [:position :frame-id])))] (rx/merge - (rx/of (dwc/commit-changes changes)) + (rx/of (dch/commit-changes changes)) (->> (rp/cmd! :update-comment-thread-position thread) (rx/catch #(rx/throw {:type :update-comment-thread-position})) (rx/ignore)))))))) diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 656173f5e4..ff477d3207 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -125,7 +125,7 @@ [parent-id] (fn [parent] (assoc-in parent [:layout-grid-cells (:id target-cell) :shapes] [(:id group)])))) - (pcb/update-shapes grid-parents ctl/assign-cells) + (pcb/update-shapes grid-parents ctl/assign-cells {:with-objects? true}) (pcb/remove-objects ids-to-delete))] [group changes])) @@ -216,7 +216,7 @@ (cond-> changes (ctl/grid-layout? objects (:parent-id shape)) - (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)))) + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells {:with-objects? true})))) selected (->> (wsh/lookup-selected state) (remove #(ctn/has-any-copy-parent? objects (get objects %))) diff --git a/frontend/src/app/main/data/workspace/guides.cljs b/frontend/src/app/main/data/workspace/guides.cljs index 5df3d41a09..2229210103 100644 --- a/frontend/src/app/main/data/workspace/guides.cljs +++ b/frontend/src/app/main/data/workspace/guides.cljs @@ -11,7 +11,7 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.types.page :as ctp] - [app.main.data.workspace.changes :as dwc] + [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -35,7 +35,7 @@ (-> (pcb/empty-changes it) (pcb/with-page page) (pcb/update-page-option :guides assoc (:id guide) guide))] - (rx/of (dwc/commit-changes changes)))))) + (rx/of (dch/commit-changes changes)))))) (defn remove-guide [guide] (dm/assert! @@ -56,7 +56,7 @@ (-> (pcb/empty-changes it) (pcb/with-page page) (pcb/update-page-option :guides dissoc (:id guide)))] - (rx/of (dwc/commit-changes changes)))))) + (rx/of (dch/commit-changes changes)))))) (defn remove-guides [ids] diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 3037b9f893..11aa8558fd 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -185,7 +185,8 @@ (fn [shape objects] (-> shape (ctl/push-into-cell [(:id first-shape)] row column) - (ctl/assign-cells objects)))) + (ctl/assign-cells objects))) + {:with-objects? true}) (pcb/reorder-grid-children [(:parent-id first-shape)]))) changes) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 497202d7c4..4566ad26af 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -499,8 +499,8 @@ changes (-> (pcb/add-object changes new-obj {:ignore-touched (and duplicating-component? child?)}) (pcb/amend-last-change #(assoc % :old-id (:id obj))) (cond-> (ctl/grid-layout? objects (:parent-id obj)) - (-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells) - (pcb/update-shapes [(:parent-id obj)] ctl/check-deassigned-cells) + (-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells {:with-objects? true}) + (pcb/update-shapes [(:parent-id obj)] ctl/check-deassigned-cells {:with-objects? true}) (pcb/reorder-grid-children [(:parent-id obj)])))) changes (cond-> changes diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index dbb65351ec..f5a1cb9368 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -19,7 +19,7 @@ [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] - [app.main.data.workspace.changes :as dwc] + [app.main.data.workspace.changes :as dch] [app.main.data.workspace.colors :as cl] [app.main.data.workspace.grid-layout.editor :as dwge] [app.main.data.workspace.modifiers :as dwm] @@ -71,13 +71,13 @@ :layout-grid-columns []}) (defn get-layout-initializer - [type from-frame? objects] + [type from-frame?] (let [[initial-layout-data calculate-params] (case type :flex [initial-flex-layout flex/calculate-params] :grid [initial-grid-layout grid/calculate-params])] - (fn [shape] + (fn [shape objects] (let [shape (-> shape (merge initial-layout-data) @@ -130,11 +130,11 @@ (let [objects (wsh/lookup-page-objects state) parent (get objects id) undo-id (js/Symbol) - layout-initializer (get-layout-initializer type from-frame? objects)] + layout-initializer (get-layout-initializer type from-frame?)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes [id] layout-initializer) - (dwc/update-shapes (dm/get-prop parent :shapes) #(dissoc % :constraints-h :constraints-v)) + (dch/update-shapes [id] layout-initializer {:with-objects? true}) + (dch/update-shapes (dm/get-prop parent :shapes) #(dissoc % :constraints-h :constraints-v)) (ptk/data-event :layout/update [id]) (dwu/commit-undo-transaction undo-id)))))) @@ -173,8 +173,8 @@ (dws/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes))) (cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1}) (create-layout-from-id new-shape-id type false) - (dwc/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto)) - (dwc/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix)) + (dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto)) + (dch/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix)) (dws/delete-shapes page-id selected) (ptk/data-event :layout/update [new-shape-id]) (dwu/commit-undo-transaction undo-id))) @@ -184,8 +184,8 @@ (dws/create-artboard-from-selection new-shape-id) (cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1}) (create-layout-from-id new-shape-id type false) - (dwc/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto)) - (dwc/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix)))) + (dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto)) + (dch/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix)))) (rx/of (ptk/data-event :layout/update [new-shape-id]) (dwu/commit-undo-transaction undo-id))))))) @@ -198,7 +198,7 @@ (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes ids #(apply dissoc % layout-keys)) + (dch/update-shapes ids #(apply dissoc % layout-keys)) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -245,7 +245,7 @@ (watch [_ _ _] (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes ids (d/patch-object changes)) + (dch/update-shapes ids (d/patch-object changes)) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -259,7 +259,7 @@ (watch [_ _ _] (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes ids (fn [shape] (case type @@ -277,12 +277,13 @@ (watch [_ _ _] (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes ids (fn [shape objects] (case type :row (ctl/remove-grid-row shape index objects) - :column (ctl/remove-grid-column shape index objects)))) + :column (ctl/remove-grid-column shape index objects))) + {:with-objects? true}) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -335,7 +336,7 @@ undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/commit-changes changes) + (dch/commit-changes changes) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -348,7 +349,7 @@ (watch [_ _ _] (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes ids (fn [shape] (case type @@ -394,7 +395,7 @@ :row :layout-grid-rows :column :layout-grid-columns)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes ids (fn [shape] (-> shape @@ -486,15 +487,16 @@ parent-ids (->> ids (map #(cfh/get-parent-id objects %))) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes ids (d/patch-object changes)) - (dwc/update-shapes children-ids (partial fix-child-sizing objects changes)) - (dwc/update-shapes + (dch/update-shapes ids (d/patch-object changes)) + (dch/update-shapes children-ids (partial fix-child-sizing objects changes)) + (dch/update-shapes parent-ids (fn [parent objects] (-> parent (fix-parent-sizing objects (set ids) changes) (cond-> (ctl/grid-layout? parent) - (ctl/assign-cells objects))))) + (ctl/assign-cells objects)))) + {:with-objects? true}) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -507,7 +509,7 @@ (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes [layout-id] (fn [shape] (->> ids @@ -530,7 +532,7 @@ (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes [layout-id] (fn [shape objects] (case mode @@ -579,7 +581,8 @@ (ctl/assign-cells objects))] (-> shape - (d/update-in-when [:layout-grid-cells (:id target-cell)] assoc :position :area)))))) + (d/update-in-when [:layout-grid-cells (:id target-cell)] assoc :position :area))))) + {:with-objects? true}) (dwge/clean-selection layout-id) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) @@ -593,7 +596,7 @@ (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes [layout-id] (fn [shape objects] (let [cells (->> ids (map #(get-in shape [:layout-grid-cells %]))) @@ -610,7 +613,8 @@ first-column (inc (- last-row first-row)) (inc (- last-column first-column))) - (ctl/assign-cells objects))))) + (ctl/assign-cells objects)))) + {:with-objects? true}) (dwge/clean-selection layout-id) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) @@ -620,14 +624,13 @@ (ptk/reify ::update-grid-cell-position ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - undo-id (js/Symbol)] + (watch [_ _ _] + (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes + (dch/update-shapes [layout-id] - (fn [shape] + (fn [shape objects] (let [prev-data (-> (dm/get-in shape [:layout-grid-cells cell-id]) (select-keys [:row :column :row-span :column-span])) @@ -636,7 +639,8 @@ (ctl/resize-cell-area (:row prev-data) (:column prev-data) (:row new-data) (:column new-data) (:row-span new-data) (:column-span new-data)) - (ctl/assign-cells objects))))) + (ctl/assign-cells objects)))) + {:with-objects? true}) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) @@ -691,6 +695,6 @@ (rx/of (dwu/start-undo-transaction undo-id) - (dwc/commit-changes changes) + (dch/commit-changes changes) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 5cc82e5b07..74d0e31f28 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -628,9 +628,13 @@ (ctl/swap-shapes id (:id next-cell))))) parent))] (-> changes - (pcb/update-shapes [(:id parent)] (fn [shape] (-> shape - (assoc :layout-grid-cells layout-grid-cells) - (ctl/assign-cells objects)))) + (pcb/update-shapes + [(:id parent)] + (fn [shape] + (-> shape + (assoc :layout-grid-cells layout-grid-cells) + ;; We want the previous objects value + (ctl/assign-cells objects)))) (pcb/reorder-grid-children [(:id parent)])))) changes diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 4b1058f618..02964dcabe 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -21,7 +21,7 @@ [app.main.data.preview :as dp] [app.main.data.viewer.shortcuts] [app.main.data.workspace :as dw] - [app.main.data.workspace.changes :as dwc] + [app.main.data.workspace.changes :as dch] [app.main.data.workspace.path.shortcuts] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shortcuts] @@ -297,7 +297,7 @@ (let [file-id (:current-file-id @st/state) changes (t/decode-str changes*)] - (st/emit! (dwc/commit-changes {:redo-changes changes + (st/emit! (dch/commit-changes {:redo-changes changes :undo-changes [] :save-undo? true :file-id file-id})))) From dc4bf82684badd89ad4b5f1fe8479640761604ca Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 29 Dec 2023 17:48:11 +0100 Subject: [PATCH 07/35] :recycle: Remove new-css-system on assets tab --- .../common/refactor/common-refactor.scss | 4 - .../styles/common/refactor/design-tokens.scss | 4 + frontend/resources/styles/main-default.scss | 1 - .../styles/main/partials/sidebar-assets.scss | 538 ------------------ .../src/app/main/ui/components/forms.scss | 3 +- .../app/main/ui/workspace/sidebar/assets.cljs | 143 ++--- .../app/main/ui/workspace/sidebar/assets.scss | 224 ++++---- .../ui/workspace/sidebar/assets/colors.cljs | 366 ++++-------- .../ui/workspace/sidebar/assets/colors.scss | 161 +++--- .../ui/workspace/sidebar/assets/common.cljs | 73 +-- .../ui/workspace/sidebar/assets/common.scss | 58 +- .../workspace/sidebar/assets/components.cljs | 445 +++++---------- .../workspace/sidebar/assets/components.scss | 381 +++++++------ .../sidebar/assets/file_library.cljs | 298 +++------- .../sidebar/assets/file_library.scss | 83 +-- .../ui/workspace/sidebar/assets/groups.cljs | 159 ++---- .../ui/workspace/sidebar/assets/groups.scss | 91 +-- .../sidebar/assets/typographies.cljs | 328 ++++------- .../sidebar/assets/typographies.scss | 63 +- 19 files changed, 1140 insertions(+), 2283 deletions(-) delete mode 100644 frontend/resources/styles/main/partials/sidebar-assets.scss diff --git a/frontend/resources/styles/common/refactor/common-refactor.scss b/frontend/resources/styles/common/refactor/common-refactor.scss index a200893e95..c1033735c8 100644 --- a/frontend/resources/styles/common/refactor/common-refactor.scss +++ b/frontend/resources/styles/common/refactor/common-refactor.scss @@ -34,7 +34,3 @@ $da-primary: var(--color-accent-primary); $da-primary-muted: var(--color-accent-primary-muted); $da-secondary: var(--color-accent-secondary); $da-tertiary: var(--color-accent-tertiary); - -#app { - background-color: var(--app-background); -} diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index a69026ba08..f9c95e3f09 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -314,3 +314,7 @@ --viewer-thumbnail-border-color: var(--color-accent-primary); --viewer-thumbnail-background-color-selected: var(--color-accent-primary-muted); } + +#app { + background-color: var(--app-background); +} diff --git a/frontend/resources/styles/main-default.scss b/frontend/resources/styles/main-default.scss index a961862db5..9271b633a6 100644 --- a/frontend/resources/styles/main-default.scss +++ b/frontend/resources/styles/main-default.scss @@ -72,7 +72,6 @@ @import "main/partials/project-bar"; @import "main/partials/sidebar"; @import "main/partials/sidebar-align-options"; -@import "main/partials/sidebar-assets"; @import "main/partials/sidebar-document-history"; @import "main/partials/sidebar-element-options"; @import "main/partials/sidebar-interactions"; diff --git a/frontend/resources/styles/main/partials/sidebar-assets.scss b/frontend/resources/styles/main/partials/sidebar-assets.scss deleted file mode 100644 index aa1750b8dd..0000000000 --- a/frontend/resources/styles/main/partials/sidebar-assets.scss +++ /dev/null @@ -1,538 +0,0 @@ -// 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 - -.assets-bar { - display: flex; - flex-direction: column; - overflow: hidden; - height: 100%; - - .assets-bar-title { - color: $color-gray-10; - font-size: $fs14; - margin: $size-2 $size-2 0 $size-2; - display: flex; - align-items: center; - cursor: pointer; - - & .libraries-button { - margin-left: auto; - display: flex; - align-items: center; - - svg { - fill: $color-gray-30; - height: 16px; - width: 16px; - padding-right: 6px; - } - } - - & .libraries-button:hover { - color: $color-primary; - - & svg { - fill: $color-primary; - } - } - } - - .search-block { - border: 1px solid $color-gray-30; - margin: $size-2 $size-2 0 $size-2; - padding: $size-1 $size-2; - display: flex; - align-items: center; - - &:hover { - border-color: $color-gray-20; - } - - &:focus-within { - border-color: $color-primary; - } - - & .search-input { - background-color: $color-gray-50; - border: none; - color: $color-gray-10; - font-size: $fs12; - margin: 0; - padding: 0; - flex-grow: 1; - - &:focus { - color: lighten($color-gray-10, 8%); - outline: none; - } - } - - & .search-icon { - display: flex; - align-items: center; - - svg { - fill: $color-gray-30; - height: 16px; - width: 16px; - } - - &.close { - transform: rotate(45deg); - cursor: pointer; - } - } - } - - .input-select { - background-color: $color-gray-50; - color: $color-gray-10; - border: 1px solid transparent; - border-bottom-color: $color-gray-40; - padding: $size-1; - margin: $size-2 $size-2 $size-4 $size-2; - - &:focus { - color: lighten($color-gray-10, 8%); - } - - &:active { - border-color: $color-primary; - } - - option { - background: $color-white; - color: $color-gray-60; - font-size: $fs12; - } - } - - .collapse-library { - margin-right: $size-2; - flex-shrink: inherit; // Inheriting shrink behaviour - - &.open svg { - transform: rotate(90deg); - } - } - - .library-bar { - cursor: pointer; - } - - .listing-options { - background-color: $color-gray-60; - display: flex; - align-items: center; - padding: $size-4 $size-2 0 $size-2; - - .selected-count { - color: $color-primary; - font-size: $fs12; - } - - .listing-option-btn { - cursor: pointer; - margin-left: $size-2; - - &.first { - margin-left: auto; - } - - svg { - fill: $color-gray-20; - height: 16px; - width: 16px; - } - } - } - - .asset-section { - background-color: $color-gray-60; - padding: $size-2; - font-size: $fs12; - color: $color-gray-20; - /* TODO: see if this is useful, or is better to leave only - one scroll bar in the whole sidebar - (also see .asset-list) */ - // max-height: 30rem; - // overflow-y: scroll; - - // First child is the listing options buttons - &:not(:nth-child(2)) { - border-top: 1px solid $color-gray-50; - } - - .asset-title { - display: flex; - cursor: pointer; - font-size: $fs12; - text-transform: uppercase; - - & .num-assets { - color: $color-gray-30; - } - - & svg { - height: 8px; - width: 8px; - fill: $color-gray-30; - margin-right: 4px; - transform: rotate(90deg); - } - - &.closed svg { - transform: rotate(0deg); - transition: transform 0.3s; - } - } - - .group-title { - display: flex; - cursor: pointer; - margin-top: $size-2; - margin-bottom: $size-1; - color: $color-white; - - & svg { - height: 8px; - width: 8px; - fill: $color-white; - margin-right: 4px; - transform: rotate(90deg); - } - - &.closed svg { - transform: rotate(0deg); - transition: transform 0.3s; - } - - & .dim { - color: $color-gray-40; - } - } - - .assets-button { - margin-left: auto; - cursor: pointer; - - & svg { - width: 0.7rem; - height: 0.7rem; - fill: #f0f0f0; - } - - &:hover svg { - fill: $color-primary; - } - } - - .asset-title + .asset-grid { - margin-top: $size-2; - } - - .asset-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - grid-auto-rows: 6vh; - column-gap: 0.5rem; - row-gap: 0.5rem; - - &.big { - grid-template-columns: repeat(2, 1fr); - grid-auto-rows: 10vh; - - .three-row & { - grid-template-columns: repeat(3, 1fr); - } - - .four-row & { - grid-template-columns: repeat(4, 1fr); - } - - .grid-cell { - padding: $size-1; - - & svg { - height: 10vh; - } - } - } - } - - .grid-cell { - background-color: $color-canvas; - border-radius: $br4; - border: 2px solid transparent; - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - padding: $size-2; - position: relative; - cursor: pointer; - - & img { - max-height: 100%; - max-width: 100%; - height: auto; - width: auto; - pointer-events: none; - } - } - - .cell-name { - background-color: $color-gray-60; - font-size: $fs9; - display: none; - position: absolute; - left: 0; - bottom: 0; - width: 100%; - padding: 3px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - &.editing { - display: block; - } - - .editable-label-input { - border: 1px solid $color-gray-20; - border-radius: $br3; - font-size: $fs12; - padding: 2px; - margin: 0; - height: unset; - width: 100%; - } - - .editable-label-close { - display: none; - } - } - - .grid-cell:hover { - border: 2px solid $color-primary; - - & .cell-name { - display: block; - } - } - - .grid-cell.selected { - border: 2px solid $color-primary; - } - - .grid-placeholder { - border: 2px solid $color-gray-20; - border-radius: $br4; - } - - .drop-space { - height: 10px; - } - - .typography-container { - position: relative; - - &:last-child { - padding-bottom: 0.5em; - } - } - - .drag-counter { - position: absolute; - top: 5px; - left: 4px; - width: 16px; - height: 16px; - background-color: $color-primary; - border-radius: 50%; - color: $color-black; - font-size: $fs12; - display: flex; - justify-content: center; - align-items: center; - } - - .asset-title + .asset-enum { - margin-top: $size-2; - } - - .asset-enum { - .enum-item { - position: relative; - display: flex; - align-items: center; - margin-bottom: $size-2; - cursor: pointer; - - & > svg, - & > img { - background-color: $color-canvas; - border-radius: $br4; - border: 2px solid transparent; - height: 24px; - width: 24px; - margin-right: $size-2; - } - - .item-name { - width: calc(100% - 24px - #{$size-2}); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - display: block; - - &.editing { - display: flex; - align-items: center; - - .editable-label-input { - height: 24px; - } - - .editable-label-close { - display: none; - } - } - } - } - - .enum-item:hover, - .enum-item.selected { - color: $color-primary; - } - - .grid-placeholder { - margin-bottom: 5px; - } - } - - /* TODO: see if this is useful, or is better to leave only - one scroll bar in the whole sidebar - (also see .asset-section) */ - // .asset-list { - // max-height: 30rem; - // overflow-y: scroll; - // } - - .asset-list-item { - display: flex; - align-items: center; - border: 1px solid transparent; - border-radius: $br3; - margin-top: $size-1; - padding: 2px; - font-size: $fs12; - color: $color-white; - cursor: pointer; - position: relative; - - .name-block { - color: $color-gray-20; - width: calc(100% - 24px - #{$size-2}); - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - & span { - margin-left: $size-1; - color: $color-gray-30; - text-transform: uppercase; - } - - &.selected { - border: 1px solid $color-primary; - } - } - - .context-menu { - position: fixed; - top: 10px; - left: 10px; - } - - .advanced-options { - border-color: $color-black; - background-color: $color-gray-60; - - .input-text, - .input-select, - .adv-typography-name { - background-color: $color-gray-60; - } - } - - .dragging { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: color.adjust($color-primary, $alpha: -0.5); - } - } -} - -.modal-create-color { - position: relative; - background-color: $color-white; - padding: 4rem; - display: flex; - flex-direction: column; - align-items: center; - - & .sketch-picker, - .chrome-picker { - box-shadow: none !important; - border: 1px solid $color-gray-10 !important; - border-radius: $br0 !important; - - & input { - background-color: $color-white; - } - } - - & .close { - position: absolute; - right: 1rem; - transform: rotate(45deg); - top: 1rem; - - svg { - fill: $color-black; - height: 20px; - width: 20px; - - &:hover { - fill: $color-danger; - } - } - } - - & .btn-primary { - width: 10rem; - padding: 0.5rem; - margin-top: 1rem; - } -} - -.modal-create-color-title { - color: $color-black; - font-size: $fs24; - font-weight: $fw400; -} - -.libraries-wrapper { - overflow: auto; - display: flex; - flex-direction: column; - flex: 1; -} diff --git a/frontend/src/app/main/ui/components/forms.scss b/frontend/src/app/main/ui/components/forms.scss index e0d10993b5..ec64c521c8 100644 --- a/frontend/src/app/main/ui/components/forms.scss +++ b/frontend/src/app/main/ui/components/forms.scss @@ -24,7 +24,7 @@ cursor: pointer; color: var(--modal-title-foreground-color); text-transform: uppercase; - + margin-bottom: $s-8; input { @extend .input-element; color: var(--input-foreground-color-active); @@ -143,6 +143,7 @@ .hint { @include titleTipography; + color: var(--modal-text-foreground-color); width: 99%; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index f82f6bb8d3..cb67bf83df 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -19,7 +19,6 @@ [app.main.ui.workspace.sidebar.assets.file-library :refer [file-library]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [app.util.keyboard :as kbd] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -71,7 +70,6 @@ [] (let [components-v2 (mf/use-ctx ctx/components-v2) read-only? (mf/use-ctx ctx/workspace-read-only?) - new-css-system (mf/use-ctx ctx/new-css-system) filters* (mf/use-state {:term "" :section "all" @@ -104,17 +102,8 @@ on-search-term-change (mf/use-fn - (mf/deps new-css-system) (fn [event] - ;; NOTE: When old-css-system is removed this function will recibe value and event - ;; Let won't be necessary any more - (let [value (if ^boolean new-css-system - event - (dom/get-target-val event))] - (swap! filters* assoc :term value)))) - - on-search-clear-click - (mf/use-fn #(swap! filters* assoc :term "")) + (swap! filters* assoc :term event))) on-section-filter-change (mf/use-fn @@ -125,23 +114,12 @@ (dom/get-attribute $ "data-test")))] (swap! filters* assoc :section value :open-menu false)))) - handle-key-down - (mf/use-fn - (fn [event] - (let [enter? (kbd/enter? event) - esc? (kbd/esc? event) - node (dom/get-target event)] - - (when ^boolean enter? (dom/blur! node)) - (when ^boolean esc? (dom/blur! node))))) - show-libraries-dialog (mf/use-fn (fn [] (modal/show! :libraries-dialog {}) (modal/allow-click-outside!))) - on-open-menu (mf/use-fn #(swap! filters* update :open-menu not)) @@ -175,86 +153,43 @@ :option-handler on-section-filter-change :data-test "typographies"}]))] - (if ^boolean new-css-system - [:div {:class (stl/css :assets-bar)} - [:div {:class (stl/css :assets-header)} - (when-not ^boolean read-only? - [:button {:class (stl/css :libraries-button) - :on-click show-libraries-dialog} - [:span {:class (stl/css :libraries-icon)} - i/library-refactor] - (tr "workspace.assets.libraries")]) + [:div {:class (stl/css :assets-bar)} + [:div {:class (stl/css :assets-header)} + (when-not ^boolean read-only? + [:button {:class (stl/css :libraries-button) + :on-click show-libraries-dialog} + [:span {:class (stl/css :libraries-icon)} + i/library-refactor] + (tr "workspace.assets.libraries")]) - [:div {:class (stl/css :search-wrapper)} - [:& search-bar {:on-change on-search-term-change - :value term - :placeholder (tr "workspace.assets.search")} - [:button - {:on-click on-open-menu - :class (stl/css :section-button)} - i/filter-refactor]] - [:& context-menu-a11y - {:on-close on-menu-close - :selectable true - :selected section - :show menu-open? - :fixed? true - :min-width? true - :top 152 - :left 64 - :options options - :workspace? true}] - [:button {:class (stl/css :sort-button) - :on-click toggle-ordering} - (if reverse-sort? - i/asc-sort-refactor - i/desc-sort-refactor)]]] + [:div {:class (stl/css :search-wrapper)} + [:& search-bar {:on-change on-search-term-change + :value term + :placeholder (tr "workspace.assets.search")} + [:button + {:on-click on-open-menu + :class (stl/css :section-button)} + i/filter-refactor]] + [:& context-menu-a11y + {:on-close on-menu-close + :selectable true + :selected section + :show menu-open? + :fixed? true + :min-width? true + :top 152 + :left 64 + :options options + :workspace? true}] + [:button {:class (stl/css :sort-button) + :on-click toggle-ordering} + (if reverse-sort? + i/asc-sort-refactor + i/desc-sort-refactor)]]] - [:& (mf/provider cmm/assets-filters) {:value filters} - [:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering} - [:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style} - [:div {:class (stl/css :libraries-wrapper)} - [:& assets-local-library {:filters filters}] - [:& assets-libraries {:filters filters}]]]]]] - - [:div.assets-bar - [:div.tool-window - [:div.tool-window-content - [:div.assets-bar-title - (tr "workspace.assets.assets") - - (when-not ^boolean read-only? - [:div.libraries-button {:on-click show-libraries-dialog} - i/text-align-justify - (tr "workspace.assets.libraries")])] - [:div.search-block - [:input.search-input - {:placeholder (tr "workspace.assets.search") - :type "text" - :value term - :on-change on-search-term-change - :on-key-down handle-key-down}] - - (if ^boolean (str/empty? term) - [:div.search-icon - i/search] - [:div.search-icon.close - {:on-click on-search-clear-click} - i/close])] - - [:select.input-select {:value (:section filters) - :data-mousetrap-dont-stop true - :on-change on-section-filter-change} - [:option {:value "all"} (tr "workspace.assets.box-filter-all")] - [:option {:value "components"} (tr "workspace.assets.components")] - (when-not components-v2 - [:option {:value "graphics"} (tr "workspace.assets.graphics")]) - [:option {:value "colors"} (tr "workspace.assets.colors")] - [:option {:value "typographies"} (tr "workspace.assets.typography")]]]] - - [:& (mf/provider cmm/assets-filters) {:value filters} - [:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering} - [:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style} - [:div.libraries-wrapper - [:& assets-local-library {:filters filters}] - [:& assets-libraries {:filters filters}]]]]]]))) + [:& (mf/provider cmm/assets-filters) {:value filters} + [:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering} + [:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style} + [:div {:class (stl/css :libraries-wrapper)} + [:& assets-local-library {:filters filters}] + [:& assets-libraries {:filters filters}]]]]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.scss b/frontend/src/app/main/ui/workspace/sidebar/assets.scss index 82f81a7ac5..dd8ebf217a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.scss @@ -10,121 +10,129 @@ position: relative; height: 100%; overflow: hidden; +} - .libraries-button { - @include tabTitleTipography; - @extend .button-secondary; - gap: $s-2; - height: $s-32; - width: 100%; - border-radius: $s-8; - margin-bottom: $s-4; - .libraries-icon { - @include flexCenter; - width: $s-24; - height: 100%; - svg { - @include flexCenter; - @extend .button-icon; - stroke: var(--icon-foreground); - } - } - &:hover { - background-color: var(--button-secondary-background-color-hover); - color: var(--button-secondary-foreground-color-hover); - border: $s-1 solid var(--button-secondary-border-color-hover); - svg { - stroke: var(--button-secondary-foreground-color-hover); - } - } - &:focus { - background-color: var(--button-secondary-background-color-focus); - color: var(--button-secondary-foreground-color-focus); - border: $s-1 solid var(--button-secondary-border-color-focus); - svg { - stroke: var(--button-secondary-foreground-color-focus); - } - } - } - .section-button { +.libraries-button { + @include tabTitleTipography; + @extend .button-secondary; + gap: $s-2; + height: $s-32; + width: 100%; + border-radius: $s-8; + margin-bottom: $s-4; + .libraries-icon { @include flexCenter; - @include buttonStyle; - height: $s-32; - width: $s-32; - margin: 0; - border: 1px solid var(--color-background-tertiary); - border-radius: $br-8 $br-2 $br-2 $br-8; - background-color: var(--color-background-tertiary); + width: $s-24; + height: 100%; svg { - height: $s-16; - width: $s-16; + @include flexCenter; + @extend .button-icon; stroke: var(--icon-foreground); } - &:focus { - border: 1px solid var(--input-border-color-focus); - outline: 0; - background-color: var(--input-background-color-active); - color: var(--input-foreground-color-active); - svg { - background-color: var(--input-background-color-active); - } - } - &:hover { - border: 1px solid var(--input-background-color-hover); - background-color: var(--input-background-color-hover); - svg { - background-color: var(--input-background-color-hover); - stroke: var(--button-foreground-hover); - } + } + &:hover { + background-color: var(--button-secondary-background-color-hover); + color: var(--button-secondary-foreground-color-hover); + border: $s-1 solid var(--button-secondary-border-color-hover); + svg { + stroke: var(--button-secondary-foreground-color-hover); } } - .sections-container { - @include menuShadow; - @include flexColumn; - position: absolute; - top: $s-84; - left: $s-12; - width: $s-192; - padding: $s-4; - border-radius: $br-8; - background-color: var(--menu-background-color); - z-index: $z-index-2; - .section-item { - @include titleTipography; - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - padding: $s-6; - border-radius: $br-8; - .section-btn { - @include buttonStyle; - } - } - } - .libraries-wrapper { - overflow-x: hidden; - overflow-y: auto; - scrollbar-gutter: stable; - display: flex; - flex-direction: column; - padding-left: $s-8; - height: calc(100vh - $s-180); - } - .assets-header { - padding: $s-8 $s-12 $s-12 $s-12; - .search-wrapper { - display: flex; - gap: $s-4; - .sort-button { - @extend .button-secondary; - width: $s-32; - border-radius: $br-8; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } + &:focus { + background-color: var(--button-secondary-background-color-focus); + color: var(--button-secondary-foreground-color-focus); + border: $s-1 solid var(--button-secondary-border-color-focus); + svg { + stroke: var(--button-secondary-foreground-color-focus); } } } + +.section-button { + @include flexCenter; + @include buttonStyle; + height: $s-32; + width: $s-32; + margin: 0; + border: 1px solid var(--color-background-tertiary); + border-radius: $br-8 $br-2 $br-2 $br-8; + background-color: var(--color-background-tertiary); + svg { + height: $s-16; + width: $s-16; + stroke: var(--icon-foreground); + } + &:focus { + border: 1px solid var(--input-border-color-focus); + outline: 0; + background-color: var(--input-background-color-active); + color: var(--input-foreground-color-active); + svg { + background-color: var(--input-background-color-active); + } + } + &:hover { + border: 1px solid var(--input-background-color-hover); + background-color: var(--input-background-color-hover); + svg { + background-color: var(--input-background-color-hover); + stroke: var(--button-foreground-hover); + } + } +} + +.sections-container { + @include menuShadow; + @include flexColumn; + position: absolute; + top: $s-84; + left: $s-12; + width: $s-192; + padding: $s-4; + border-radius: $br-8; + background-color: var(--menu-background-color); + z-index: $z-index-2; +} + +.section-item { + @include titleTipography; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: $s-6; + border-radius: $br-8; +} + +.section-btn { + @include buttonStyle; +} + +.libraries-wrapper { + overflow-x: hidden; + overflow-y: auto; + scrollbar-gutter: stable; + display: flex; + flex-direction: column; + padding-left: $s-8; + height: calc(100vh - $s-180); +} + +.assets-header { + padding: $s-8 $s-12 $s-12 $s-12; +} + +.search-wrapper { + display: flex; + gap: $s-4; +} + +.sort-button { + @extend .button-secondary; + width: $s-32; + border-radius: $br-8; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs index 9ea7a1f6c8..d819943033 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.assets.colors - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -18,7 +18,6 @@ [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.color-bullet :as bc] [app.main.ui.components.color-bullet-new :as cb] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] @@ -59,7 +58,6 @@ menu-state (mf/use-state cmm/initial-context-menu-state) read-only? (mf/use-ctx ctx/workspace-read-only?) - new-css-system (mf/use-ctx ctx/new-css-system) default-name (cond (:gradient color) (uc/gradient-type->string (dm/get-in color [:gradient :type])) @@ -193,113 +191,67 @@ (dom/select-text! input) nil))) - (if ^boolean new-css-system - [:div {:class (dom/classnames (css :asset-list-item) true - (css :selected) (contains? selected (:id color)) - (css :editing) editing?) - :style #js {"--bullet-size" "16px"} - :on-context-menu on-context-menu - :on-click (when-not editing? on-click) - :ref item-ref - :draggable (and (not read-only?) (not editing?)) - :on-drag-start on-color-drag-start - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} + [:div {:class (stl/css-case :asset-list-item true + :selected (contains? selected (:id color)) + :editing editing?) + :style #js {"--bullet-size" "16px"} + :on-context-menu on-context-menu + :on-click (when-not editing? on-click) + :ref item-ref + :draggable (and (not read-only?) (not editing?)) + :on-drag-start on-color-drag-start + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} - [:div {:class (dom/classnames (css :bullet-block) true)} - [:& cb/color-bullet {:color color - :mini? true}]] + [:div {:class (stl/css :bullet-block)} + [:& cb/color-bullet {:color color + :mini? true}]] - (if ^boolean editing? - [:input - {:type "text" - :class (dom/classnames (css :element-name) true) - :ref input-ref - :on-blur input-blur - :on-key-down input-key-down - :auto-focus true - :default-value (cfh/merge-path-item (:path color) (:name color))}] + (if ^boolean editing? + [:input + {:type "text" + :class (stl/css :element-name) + :ref input-ref + :on-blur input-blur + :on-key-down input-key-down + :auto-focus true + :default-value (cfh/merge-path-item (:path color) (:name color))}] - [:div {:title (:name color) - :class (dom/classnames (css :name-block) true) - :on-double-click rename-color-clicked} + [:div {:title (:name color) + :class (stl/css :name-block) + :on-double-click rename-color-clicked} - (if (= (:name color) default-name) - [:span {:class (dom/classnames (css :default-name-only) true)} default-name] - [:* - [:span {:class (dom/classnames (css :name) true)} (:name color)] - [:span {:class (dom/classnames (css :default-name) true)} default-name]])]) + (if (= (:name color) default-name) + [:span {:class (stl/css :default-name-only)} default-name] + [:* + [:span {:class (stl/css :name)} (:name color)] + [:span {:class (stl/css :default-name)} default-name]])]) - (when local? - [:& cmm/assets-context-menu - {:on-close on-close-menu - :state @menu-state - :options [(when-not (or multi-colors? multi-assets?) - {:option-name (tr "workspace.assets.rename") - :id "assets-rename-color" - :option-handler rename-color-clicked}) - (when-not (or multi-colors? multi-assets?) - {:option-name (tr "workspace.assets.edit") - :id "assets-edit-color" - :option-handler edit-color-clicked}) + (when local? + [:& cmm/assets-context-menu + {:on-close on-close-menu + :state @menu-state + :options [(when-not (or multi-colors? multi-assets?) + {:option-name (tr "workspace.assets.rename") + :id "assets-rename-color" + :option-handler rename-color-clicked}) + (when-not (or multi-colors? multi-assets?) + {:option-name (tr "workspace.assets.edit") + :id "assets-edit-color" + :option-handler edit-color-clicked}) - {:option-name (tr "workspace.assets.delete") - :id "assets-delete-color" - :option-handler delete-color} - (when-not multi-assets? - {:option-name (tr "workspace.assets.group") - :id "assets-group-color" - :option-handler (on-group (:id color))})]}]) + {:option-name (tr "workspace.assets.delete") + :id "assets-delete-color" + :option-handler delete-color} + (when-not multi-assets? + {:option-name (tr "workspace.assets.group") + :id "assets-group-color" + :option-handler (on-group (:id color))})]}]) - (when ^boolean dragging? - [:div {:class (dom/classnames (css :dragging) true)}])] - - [:div.asset-list-item - {:class-name (dom/classnames - :selected (contains? selected (:id color))) - :on-context-menu on-context-menu - :on-click (when-not editing? on-click) - :ref item-ref - :draggable (and (not read-only?) (not editing?)) - :on-drag-start on-color-drag-start - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - - [:& bc/color-bullet {:color color}] - - (if ^boolean editing? - [:input.element-name - {:type "text" - :ref input-ref - :on-blur input-blur - :on-key-down input-key-down - :auto-focus true - :default-value (cfh/merge-path-item (:path color) (:name color))}] - - [:div.name-block {:title (:name color) - :on-double-click rename-color-clicked} - (:name color) - (when-not (= (:name color) default-name) - [:span default-name])]) - - (when local? - [:& cmm/assets-context-menu - {:on-close on-close-menu - :state @menu-state - :options [(when-not (or multi-colors? multi-assets?) - [(tr "workspace.assets.rename") rename-color-clicked]) - (when-not (or multi-colors? multi-assets?) - [(tr "workspace.assets.edit") edit-color-clicked]) - [(tr "workspace.assets.delete") delete-color] - (when-not multi-assets? - [(tr "workspace.assets.group") (on-group (:id color))])]}]) - - (when ^boolean dragging? - [:div.dragging])]))) + (when ^boolean dragging? + [:div {:class (stl/css :dragging)}])])) (mf/defc colors-group [{:keys [file-id prefix groups open-groups force-open? local? selected @@ -308,7 +260,6 @@ selected-full]}] (let [group-open? (or ^boolean force-open? ^boolean (get open-groups prefix (if (= prefix "") true false))) - new-css-system (mf/use-ctx ctx/new-css-system) dragging* (mf/use-state false) dragging? (deref dragging*) @@ -338,136 +289,71 @@ (fn [event] (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full move-color)))] - (if ^boolean new-css-system - [:div {:class (dom/classnames (css :colors-group) true) - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - [:& grp/asset-group-title {:file-id file-id - :section :colors - :path prefix - :group-open? group-open? - :on-rename on-rename-group - :on-ungroup on-ungroup}] - (when group-open? - [:* - (let [colors (get groups "" [])] - [:div {:class (dom/classnames (css :asset-list) true) - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} + [:div {:class (stl/css :colors-group) + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} + [:& grp/asset-group-title {:file-id file-id + :section :colors + :path prefix + :group-open? group-open? + :on-rename on-rename-group + :on-ungroup on-ungroup}] + (when group-open? + [:* + (let [colors (get groups "" [])] + [:div {:class (stl/css :asset-list) + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} - (when ^boolean dragging? - [:div {:class (dom/classnames (css :grid-placeholder) true)} - "\u00A0"]) + (when ^boolean dragging? + [:div {:class (stl/css :grid-placeholder)} + "\u00A0"]) - (when (and (empty? colors) - (some? groups)) - [:div {:class (dom/classnames (css :drop-space) true)}]) + (when (and (empty? colors) + (some? groups)) + [:div {:class (stl/css :drop-space)}]) - (for [color colors] - [:& color-item {:key (dm/str (:id color)) - :color color - :file-id file-id - :local? local? - :selected selected - :multi-colors? multi-colors? - :multi-assets? multi-assets? - :on-asset-click on-asset-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection - :on-group on-group - :colors colors - :selected-full selected-full - :selected-paths selected-paths - :move-color move-color}])]) + (for [color colors] + [:& color-item {:key (dm/str (:id color)) + :color color + :file-id file-id + :local? local? + :selected selected + :multi-colors? multi-colors? + :multi-assets? multi-assets? + :on-asset-click on-asset-click + :on-assets-delete on-assets-delete + :on-clear-selection on-clear-selection + :on-group on-group + :colors colors + :selected-full selected-full + :selected-paths selected-paths + :move-color move-color}])]) - (for [[path-item content] groups] - (when-not (empty? path-item) - [:& colors-group {:file-id file-id - :prefix (cfh/merge-path-item prefix path-item) - :key (dm/str "group-" path-item) - :groups content - :open-groups open-groups - :force-open? force-open? - :local? local? - :selected selected - :multi-colors? multi-colors? - :multi-assets? multi-assets? - :on-asset-click on-asset-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection - :on-group on-group - :on-rename-group on-rename-group - :on-ungroup on-ungroup - :colors colors - :selected-full selected-full}]))])] - - - [:div {:on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - [:& grp/asset-group-title {:file-id file-id - :section :colors - :path prefix - :group-open? group-open? - :on-rename on-rename-group - :on-ungroup on-ungroup}] - (when group-open? - [:* - (let [colors (get groups "" [])] - [:div.asset-list {:on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - - (when ^boolean dragging? - [:div.grid-placeholder "\u00A0"]) - - (when (and (empty? colors) - (some? groups)) - [:div.drop-space]) - - (for [color colors] - [:& color-item {:key (dm/str (:id color)) - :color color - :file-id file-id - :local? local? - :selected selected - :multi-colors? multi-colors? - :multi-assets? multi-assets? - :on-asset-click on-asset-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection - :on-group on-group - :colors colors - :selected-full selected-full - :selected-paths selected-paths - :move-color move-color}])]) - - (for [[path-item content] groups] - (when-not (empty? path-item) - [:& colors-group {:file-id file-id - :prefix (cfh/merge-path-item prefix path-item) - :key (dm/str "group-" path-item) - :groups content - :open-groups open-groups - :force-open? force-open? - :local? local? - :selected selected - :multi-colors? multi-colors? - :multi-assets? multi-assets? - :on-asset-click on-asset-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection - :on-group on-group - :on-rename-group on-rename-group - :on-ungroup on-ungroup - :colors colors - :selected-full selected-full}]))])]))) + (for [[path-item content] groups] + (when-not (empty? path-item) + [:& colors-group {:file-id file-id + :prefix (cfh/merge-path-item prefix path-item) + :key (dm/str "group-" path-item) + :groups content + :open-groups open-groups + :force-open? force-open? + :local? local? + :selected selected + :multi-colors? multi-colors? + :multi-assets? multi-assets? + :on-asset-click on-asset-click + :on-assets-delete on-assets-delete + :on-clear-selection on-clear-selection + :on-group on-group + :on-rename-group on-rename-group + :on-ungroup on-ungroup + :colors colors + :selected-full selected-full}]))])])) (mf/defc colors-section [{:keys [file-id local? colors open? force-open? open-status-ref selected reverse-sort? @@ -491,7 +377,6 @@ (grp/group-assets colors reverse-sort?)) read-only? (mf/use-ctx ctx/workspace-read-only?) - new-css-system (mf/use-ctx ctx/new-css-system) add-color (mf/use-fn (fn [value _] @@ -589,19 +474,12 @@ :section :colors :assets-count (count colors) :open? open?} - (if ^boolean new-css-system - (when local? - [:& cmm/asset-section-block {:role :title-button} - (when-not read-only? - [:button {:class (dom/classnames (css :assets-btn) true) - :on-click add-color-clicked} - i/add-refactor])]) - - (when local? - [:& cmm/asset-section-block {:role :title-button} - (when-not read-only? - [:div.assets-button {:on-click add-color-clicked} - i/plus])])) + (when local? + [:& cmm/asset-section-block {:role :title-button} + (when-not read-only? + [:button {:class (stl/css :assets-btn) + :on-click add-color-clicked} + i/add-refactor])]) [:& cmm/asset-section-block {:role :content} diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss index aed7ab1197..28dced5b49 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss @@ -9,7 +9,7 @@ .assets-btn { @extend .button-tertiary; height: $s-32; - width: calc($s-24 + $s-4); + width: $s-28; padding: 0; border-radius: $br-8; svg { @@ -20,83 +20,92 @@ .colors-group { margin-top: $s-4; - .asset-list { - padding: 0 0 0 $s-4; - .asset-list-item { - position: relative; - display: flex; - align-items: center; - height: $s-32; - padding: $s-8; - margin-bottom: $s-4; - border-radius: $br-8; - background-color: var(--assets-item-background-color); - cursor: pointer; - .bullet-block { - @include flexCenter; - height: 100%; - justify-content: flex-start; - margin-right: $s-4; - } - .name-block { - @include titleTipography; - display: grid; - grid-template-columns: auto 1fr; - margin: 0; - overflow: hidden; - .default-name-only, - .name { - color: var(--assets-item-name-foreground-color-hover); - margin-right: $s-6; - @include textEllipsis; - } - .default-name { - min-width: 0; - color: var(--assets-item-name-foreground-color); - } - } - .element-name { - @include textEllipsis; - color: var(--color-foreground-primary); - } - &.selected { - border: $s-1 solid var(--assets-item-border-color); - } +} - &.editing { - border: $s-1 solid var(--input-border-color-focus); - input.element-name { - @include textEllipsis; - @include titleTipography; - @include removeInputStyle; - flex-grow: 1; - height: $s-28; - max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); - margin: 0; - color: var(--layer-row-foreground-color); - } - } - &:hover { - background-color: var(--assets-item-background-color-hover); - } +.asset-list { + padding: 0 0 0 $s-4; +} + +.asset-list-item { + position: relative; + display: flex; + align-items: center; + height: $s-32; + padding: $s-8; + margin-bottom: $s-4; + border-radius: $br-8; + background-color: var(--assets-item-background-color); + cursor: pointer; + + &.selected { + border: $s-1 solid var(--assets-item-border-color); + } + + &.editing { + border: $s-1 solid var(--input-border-color-focus); + input.element-name { + @include textEllipsis; + @include titleTipography; + @include removeInputStyle; + flex-grow: 1; + height: $s-28; + max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); + margin: 0; + color: var(--layer-row-foreground-color); } } - .grid-placeholder { - height: $s-2; - margin-bottom: $s-2; - background-color: var(--color-accent-primary); - } - .drop-space { - height: $s-12; - } - .dragging { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border-radius: $s-8; - background-color: var(--assets-item-background-color-drag); - border: $s-2 solid var(--assets-item-border-color-drag); + &:hover { + background-color: var(--assets-item-background-color-hover); } } + +.bullet-block { + @include flexCenter; + height: 100%; + justify-content: flex-start; + margin-right: $s-4; +} + +.name-block { + @include titleTipography; + display: grid; + grid-template-columns: auto 1fr; + margin: 0; + overflow: hidden; + .default-name-only, + .name { + color: var(--assets-item-name-foreground-color-hover); + margin-right: $s-6; + @include textEllipsis; + } + .default-name { + min-width: 0; + color: var(--assets-item-name-foreground-color); + } +} + +.element-name { + @include textEllipsis; + color: var(--color-foreground-primary); +} + +.grid-placeholder { + height: $s-2; + margin-bottom: $s-2; + background-color: var(--color-accent-primary); +} + +.drop-space { + height: $s-12; +} + +.dragging { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: $s-8; + background-color: var(--assets-item-background-color-drag); + border: $s-2 solid var(--assets-item-border-color-drag); +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs index 141a83a68f..c6d63c7d3e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs @@ -6,7 +6,7 @@ (ns app.main.ui.workspace.sidebar.assets.common - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] @@ -22,7 +22,6 @@ [app.main.refs :as refs] [app.main.render :refer [component-svg component-svg-thumbnail]] [app.main.store :as st] - [app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]] [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.context :as ctx] @@ -111,24 +110,14 @@ (mf/defc assets-context-menu {::mf/wrap-props false} [{:keys [options state on-close]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& context-menu-a11y - {:show (:open? state) - :fixed? (or (not= (:top state) 0) (not= (:left state) 0)) - :on-close on-close - :top (:top state) - :left (:left state) - :options options - :workspace? true}] - - [:& context-menu - {:selectable false - :show (:open? state) - :on-close on-close - :top (:top state) - :left (:left state) - :options options}]))) + [:& context-menu-a11y + {:show (:open? state) + :fixed? (or (not= (:top state) 0) (not= (:left state) 0)) + :on-close on-close + :top (:top state) + :left (:left state) + :options options + :workspace? true}]) (mf/defc section-icon [{:keys [section] :as props}] @@ -145,34 +134,24 @@ (filter some?)) get-role #(.. % -props -role) title-buttons (filter #(= (get-role %) :title-button) children) - content (filter #(= (get-role %) :content) children) - new-css-system (mf/use-ctx ctx/new-css-system)] - (if ^boolean new-css-system - [:div {:class (dom/classnames (css :asset-section) true)} - [:& title-bar {:collapsable? true - :collapsed? (not open?) - :clickable-all? true - :on-collapsed #(st/emit! (dw/set-assets-section-open file-id section (not open?))) - :class (css :title-spacing) - :title (mf/html [:span {:class (dom/classnames (css :title-name) true)} - [:span {:class (dom/classnames (css :section-icon) true)} - [:& section-icon {:section section}]] - [:span {:class (dom/classnames (css :section-name) true)} - title] + content (filter #(= (get-role %) :content) children)] + [:div {:class (stl/css :asset-section)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :clickable-all? true + :on-collapsed #(st/emit! (dw/set-assets-section-open file-id section (not open?))) + :class (stl/css :title-spacing) + :title (mf/html [:span {:class (stl/css :title-name)} + [:span {:class (stl/css :section-icon)} + [:& section-icon {:section section}]] + [:span {:class (stl/css :section-name)} + title] - [:span {:class (dom/classnames (css :num-assets) true)} - assets-count]])} - title-buttons] - (when ^boolean open? - content)] - [:div.asset-section - [:div.asset-title {:class (when (not ^boolean open?) "closed")} - [:span {:on-click #(st/emit! (dw/set-assets-section-open file-id section (not open?)))} - i/arrow-slide title] - [:span.num-assets (dm/str "\u00A0(") assets-count ")"] ;; Unicode 00A0 is non-breaking space - title-buttons] - (when ^boolean open? - content)]))) + [:span {:class (stl/css :num-assets)} + assets-count]])} + title-buttons] + (when ^boolean open? + content)])) (mf/defc asset-section-block [{:keys [children]}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss index 21da5c603c..a546e71a7d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss @@ -6,36 +6,38 @@ @import "refactor/common-refactor.scss"; -.asset-section { - .title-name { - @include tabTitleTipography; - display: flex; - align-items: center; - flex-grow: 1; - width: 100%; - .section-icon { - @include flexCenter; - padding-right: $s-2; - svg { - @include flexCenter; - height: $s-16; - width: $s-16; - color: transparent; - fill: none; - } - } - .section-name { - display: flex; - align-items: center; - margin: 0 $s-2; - } - .num-assets { - @include flexCenter; - height: 100%; - padding-left: $s-8; - } +.title-name { + @include tabTitleTipography; + display: flex; + align-items: center; + flex-grow: 1; + width: 100%; +} + +.section-icon { + @include flexCenter; + padding-right: $s-2; + svg { + @include flexCenter; + height: $s-16; + width: $s-16; + color: transparent; + fill: none; } } + +.section-name { + display: flex; + align-items: center; + margin: 0 $s-2; +} + +.num-assets { + @include flexCenter; + height: 100%; + padding-left: $s-8; +} + .title-spacing { margin-bottom: $s-4; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs index 964b403802..833c573f7a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.assets.components - (:require-macros [app.main.style :as stl :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -77,7 +77,6 @@ read-only? (mf/use-ctx ctx/workspace-read-only?) components-v2 (mf/use-ctx ctx/components-v2) - new-css-system (mf/use-ctx ctx/new-css-system) component-id (:id component) visible? (h/use-visible item-ref :once? true) @@ -144,89 +143,45 @@ (mf/deps on-context-menu component-id) (partial on-context-menu component-id))] - (if ^boolean new-css-system - [:div {:ref item-ref - :class (dom/classnames - (css :selected) (contains? selected (:id component)) - (css :grid-cell) listing-thumbs? - (css :enum-item) (not listing-thumbs?)) - :id (dm/str "component-shape-id-" (:id component)) - :draggable (not read-only?) - :on-click on-component-click - :on-double-click on-component-double-click - :on-context-menu on-context-menu - :on-drag-start on-component-drag-start - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - (when (and (some? root-shape) - (some? container)) - [:* + [:div {:ref item-ref + :class (stl/css-case :selected (contains? selected (:id component)) + :grid-cell listing-thumbs? + :enum-item (not listing-thumbs?)) + :id (dm/str "component-shape-id-" (:id component)) + :draggable (not read-only?) + :on-click on-component-click + :on-double-click on-component-double-click + :on-context-menu on-context-menu + :on-drag-start on-component-drag-start + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} + (when (and (some? root-shape) + (some? container)) + [:* + (let [renaming? (= renaming (:id component))] + [:* + [:& editable-label + {:class (stl/css-case :cell-name listing-thumbs? + :item-name (not listing-thumbs?) + :editing renaming?) + :value (cfh/merge-path-item (:path component) (:name component)) + :tooltip (cfh/merge-path-item (:path component) (:name component)) + :display-value (:name component) + :editing renaming? + :disable-dbl-click true + :on-change do-rename + :on-cancel cancel-rename}] - (let [renaming? (= renaming (:id component))] - [:* - [:& editable-label - {:class (dom/classnames - (css :cell-name) listing-thumbs? - (css :item-name) (not listing-thumbs?) - (css :editing) renaming?) - :value (cfh/merge-path-item (:path component) (:name component)) - :tooltip (cfh/merge-path-item (:path component) (:name component)) - :display-value (:name component) - :editing renaming? - :disable-dbl-click true - :on-change do-rename - :on-cancel cancel-rename}] + (when ^boolean dragging? + [:div {:class (stl/css :dragging)}])]) - (when ^boolean dragging? - [:div {:class (dom/classnames (css :dragging) true)}])]) + (when visible? [:& cmm/component-item-thumbnail {:file-id file-id :root-shape root-shape :component component - :container container}]])] - - [:div {:ref item-ref - :class (dom/classnames - :selected (contains? selected (:id component)) - :grid-cell listing-thumbs? - :enum-item (not listing-thumbs?)) - :id (dm/str "component-shape-id-" (:id component)) - :draggable (not read-only?) - :on-click on-component-click - :on-double-click on-component-double-click - :on-context-menu on-context-menu - :on-drag-start on-component-drag-start - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - - (when (and (some? root-shape) - (some? container)) - [:* - (when visible? - [:& cmm/component-item-thumbnail {:file-id file-id - :root-shape root-shape - :component component - :container container}]) - (let [renaming? (= renaming (:id component))] - [:* - [:& editable-label - {:class (dom/classnames - :cell-name listing-thumbs? - :item-name (not listing-thumbs?) - :editing renaming?) - :value (cfh/merge-path-item (:path component) (:name component)) - :tooltip (cfh/merge-path-item (:path component) (:name component)) - :display-value (:name component) - :editing renaming? - :disable-dbl-click true - :on-change do-rename - :on-cancel cancel-rename}] - - (when ^boolean dragging? - [:div.dragging])])])]))) + :container container}])])])) (mf/defc components-group {::mf/wrap-props false} @@ -236,7 +191,6 @@ (let [group-open? (or ^boolean force-open? ^boolean (get open-groups prefix (if (= prefix "") true false))) - new-css-system (mf/use-ctx ctx/new-css-system) dragging* (mf/use-state false) dragging? (deref dragging*) @@ -266,162 +220,82 @@ (when (and local (:local? @drag-data*)) (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full dwl/rename-component-and-main-instance))))] - (if ^boolean new-css-system - [:div {:class (dom/classnames (css :component-group) true) - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - [:& grp/asset-group-title - {:file-id file-id - :section :components - :path prefix - :group-open? group-open? - :on-rename on-rename-group - :on-ungroup on-ungroup}] + [:div {:class (stl/css :component-group) + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} + [:& grp/asset-group-title + {:file-id file-id + :section :components + :path prefix + :group-open? group-open? + :on-rename on-rename-group + :on-ungroup on-ungroup}] - (when group-open? - [:* - (let [components (get groups "" [])] - [:div {:class-name (dom/classnames - (css :asset-grid) listing-thumbs? - (css :asset-enum) (not listing-thumbs?) - (css :drop-space) (and - (empty? components) - (some? groups) - (not dragging?) - local)) - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} + (when group-open? + [:* + (let [components (get groups "" [])] + [:div {:class-name (stl/css-case :asset-grid listing-thumbs? + :asset-enum (not listing-thumbs?) + :drop-space (and + (empty? components) + (some? groups) + (not dragging?) + local)) + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} - (when ^boolean dragging? - [:div {:class (dom/classnames (css :grid-placeholder) true)} "\u00A0"]) + (when ^boolean dragging? + [:div {:class (stl/css :grid-placeholder)} "\u00A0"]) - (when (and (empty? components) - (some? groups) - local) - [:div {:class (dom/classnames (css :drop-space) true)}]) + (when (and (empty? components) + (some? groups) + local) + [:div {:class (stl/css :drop-space)}]) - (for [component components] - [:& components-item - {:component component - :key (dm/str "component-" (:id component)) - :renaming renaming - :listing-thumbs? listing-thumbs? - :file-id file-id - :selected selected - :selected-full selected-full - :selected-paths selected-paths - :on-asset-click on-asset-click - :on-context-menu on-context-menu - :on-drag-start on-drag-start - :on-group on-group - :do-rename do-rename - :cancel-rename cancel-rename - :local local}])]) + (for [component components] + [:& components-item + {:component component + :key (dm/str "component-" (:id component)) + :renaming renaming + :listing-thumbs? listing-thumbs? + :file-id file-id + :selected selected + :selected-full selected-full + :selected-paths selected-paths + :on-asset-click on-asset-click + :on-context-menu on-context-menu + :on-drag-start on-drag-start + :on-group on-group + :do-rename do-rename + :cancel-rename cancel-rename + :local local}])]) - (for [[path-item content] groups] - (when-not (empty? path-item) - [:& components-group {:file-id file-id - :key path-item - :prefix (cfh/merge-path-item prefix path-item) - :groups content - :open-groups open-groups - :force-open? force-open? - :renaming renaming - :listing-thumbs? listing-thumbs? - :selected selected - :on-asset-click on-asset-click - :on-drag-start on-drag-start - :do-rename do-rename - :cancel-rename cancel-rename - :on-rename-group on-rename-group - :on-ungroup on-ungroup - :on-context-menu on-context-menu - :selected-full selected-full - :local local}]))])] - - - [:div {:on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - - [:& grp/asset-group-title - {:file-id file-id - :section :components - :path prefix - :group-open? group-open? - :on-rename on-rename-group - :on-ungroup on-ungroup}] - - (when group-open? - [:* - (let [components (get groups "" [])] - [:div {:class-name (dom/classnames - :asset-grid listing-thumbs? - :big listing-thumbs? - :asset-enum (not listing-thumbs?) - :drop-space (and - (empty? components) - (some? groups) - (not dragging?) - local)) - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - - (when ^boolean dragging? - [:div.grid-placeholder "\u00A0"]) - - (when (and (empty? components) - (some? groups) - local) - [:div.drop-space]) - - (for [component components] - [:& components-item - {:component component - :key (dm/str "component-" (:id component)) - :renaming renaming - :listing-thumbs? listing-thumbs? - :file-id file-id - :selected selected - :selected-full selected-full - :selected-paths selected-paths - :on-asset-click on-asset-click - :on-context-menu on-context-menu - :on-drag-start on-drag-start - :on-group on-group - :do-rename do-rename - :cancel-rename cancel-rename - :local local}])]) - - (for [[path-item content] groups] - (when-not (empty? path-item) - [:& components-group {:file-id file-id - :key path-item - :prefix (cfh/merge-path-item prefix path-item) - :groups content - :open-groups open-groups - :force-open? force-open? - :renaming renaming - :listing-thumbs? listing-thumbs? - :selected selected - :on-asset-click on-asset-click - :on-drag-start on-drag-start - :do-rename do-rename - :cancel-rename cancel-rename - :on-rename-group on-rename-group - :on-ungroup on-ungroup - :on-context-menu on-context-menu - :selected-full selected-full - :local local}]))])]))) + (for [[path-item content] groups] + (when-not (empty? path-item) + [:& components-group {:file-id file-id + :key path-item + :prefix (cfh/merge-path-item prefix path-item) + :groups content + :open-groups open-groups + :force-open? force-open? + :renaming renaming + :listing-thumbs? listing-thumbs? + :selected selected + :on-asset-click on-asset-click + :on-drag-start on-drag-start + :do-rename do-rename + :cancel-rename cancel-rename + :on-rename-group on-rename-group + :on-ungroup on-ungroup + :on-context-menu on-context-menu + :selected-full selected-full + :local local}]))])])) (mf/defc components-section {::mf/wrap-props false} @@ -446,7 +320,6 @@ menu-state (mf/use-state cmm/initial-context-menu-state) read-only? (mf/use-ctx ctx/workspace-read-only?) components-v2 (mf/use-ctx ctx/components-v2) - new-css-system (mf/use-ctx ctx/new-css-system) toggle-list-style (mf/use-ctx cmm/assets-toggle-list-style) selected (:components selected) @@ -623,38 +496,28 @@ :section :components :assets-count (count components) :open? open?} - (if ^boolean new-css-system - [:& cmm/asset-section-block {:role :title-button} - [:* - (when open? - [:div {:class (stl/css :listing-options)} - [:& radio-buttons {:selected (if listing-thumbs? "grid" "list") - :on-change toggle-list-style - :name "listing-style"} - [:& radio-button {:icon i/view-as-list-refactor - :value "list" - :id "opt-list"}] - [:& radio-button {:icon i/flex-grid-refactor - :value "grid" - :id "opt-grid"}]]]) + [:& cmm/asset-section-block {:role :title-button} + [:* + (when open? + [:div {:class (stl/css :listing-options)} + [:& radio-buttons {:selected (if listing-thumbs? "grid" "list") + :on-change toggle-list-style + :name "listing-style"} + [:& radio-button {:icon i/view-as-list-refactor + :value "list" + :id "opt-list"}] + [:& radio-button {:icon i/flex-grid-refactor + :value "grid" + :id "opt-grid"}]]]) - (when (and components-v2 (not read-only?) local?) - [:div {:on-click add-component - :class (dom/classnames (css :add-component) true)} - i/add-refactor - [:& file-uploader {:accept cm/str-image-types - :multi true - :ref input-ref - :on-selected on-file-selected}]])]] - (when local? - [:& cmm/asset-section-block {:role :title-button} - (when (and components-v2 (not read-only?)) - [:div.assets-button {:on-click add-component} - i/plus - [:& file-uploader {:accept cm/str-image-types - :multi true - :ref input-ref - :on-selected on-file-selected}]])])) + (when (and components-v2 (not read-only?) local?) + [:div {:on-click add-component + :class (stl/css :add-component)} + i/add-refactor + [:& file-uploader {:accept cm/str-image-types + :multi true + :ref input-ref + :on-selected on-file-selected}]])]] [:& cmm/asset-section-block {:role :content} (when ^boolean open? @@ -680,42 +543,28 @@ [:& cmm/assets-context-menu {:on-close on-close-menu :state @menu-state - :options (if new-css-system - [(when (and local? (not (or multi-components? multi-assets? read-only?))) - {:option-name (tr "workspace.assets.rename") - :id "assets-rename-component" - :option-handler on-rename}) - (when (and local? (not (or multi-assets? read-only?))) - {:option-name (if components-v2 - (tr "workspace.assets.duplicate-main") - (tr "workspace.assets.duplicate")) - :id "assets-duplicate-component" - :option-handler on-duplicate}) + :options [(when (and local? (not (or multi-components? multi-assets? read-only?))) + {:option-name (tr "workspace.assets.rename") + :id "assets-rename-component" + :option-handler on-rename}) + (when (and local? (not (or multi-assets? read-only?))) + {:option-name (if components-v2 + (tr "workspace.assets.duplicate-main") + (tr "workspace.assets.duplicate")) + :id "assets-duplicate-component" + :option-handler on-duplicate}) - (when (and local? (not read-only?)) - {:option-name (tr "workspace.assets.delete") - :id "assets-delete-component" - :option-handler on-delete}) - (when (and local? (not (or multi-assets? read-only?))) - {:option-name (tr "workspace.assets.group") - :id "assets-group-component" - :option-handler on-group}) + (when (and local? (not read-only?)) + {:option-name (tr "workspace.assets.delete") + :id "assets-delete-component" + :option-handler on-delete}) + (when (and local? (not (or multi-assets? read-only?))) + {:option-name (tr "workspace.assets.group") + :id "assets-group-component" + :option-handler on-group}) - (when (and components-v2 (not multi-assets?)) - {:option-name (tr "workspace.shape.menu.show-main") - :id "assets-show-main-component" - :option-handler on-show-main})] - - [(when (and local? (not (or multi-components? multi-assets? read-only?))) - [(tr "workspace.assets.rename") on-rename]) - (when (and local? (not (or multi-assets? read-only?))) - [(if components-v2 - (tr "workspace.assets.duplicate-main") - (tr "workspace.assets.duplicate")) on-duplicate]) - (when (and local? (not read-only?)) - [(tr "workspace.assets.delete") on-delete]) - (when (and local? (not (or multi-assets? read-only?))) - [(tr "workspace.assets.group") on-group]) - (when (and components-v2 (not multi-assets?)) - [(tr "workspace.shape.menu.show-main") on-show-main])])}]]])) + (when (and components-v2 (not multi-assets?)) + {:option-name (tr "workspace.shape.menu.show-main") + :id "assets-show-main-component" + :option-handler on-show-main})]}]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss index 82fa009bc6..6496b917eb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss @@ -6,213 +6,217 @@ @import "refactor/common-refactor.scss"; -.component-group { - .drop-space { - height: $s-12; - } - .asset-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-auto-rows: calc(10vh + $s-16); - gap: $s-4; - margin-left: $s-8; - .grid-cell { - @include flexCenter; - position: relative; - padding: $s-8; - border: $s-4 solid transparent; - border-radius: $br-8; - background-color: var(--assets-component-background-color); - overflow: hidden; - cursor: pointer; - img { - height: auto; - width: auto; - max-height: 100%; - max-width: 100%; - pointer-events: none; - } - svg { - height: 10vh; - } - .cell-name { - @include titleTipography; - @include textEllipsis; - display: none; - position: absolute; - left: 0; - bottom: 0; - width: 100%; - padding: $s-2; - &.editing { - display: flex; - align-items: center; - height: $s-32; - border: $s-1 solid var(--input-border-color-focus); - border-radius: $br-8; - background-color: var(--input-background-color); - input { - @include textEllipsis; - @include titleTipography; - @include removeInputStyle; - flex-grow: 1; - height: $s-28; - max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); - padding-left: $s-6; - margin: 0; - border-radius: $br-8; - color: var(--input-foreground-color); - } - span { - @include flexCenter; - height: $s-28; - background-color: transparent; - border-radius: $br-8; - svg { - @extend .button-icon-small; - stroke: var(--input-foreground-color); - transform: rotate(90deg); - } - } - } - } +.drop-space { + height: $s-12; +} +.asset-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-auto-rows: calc(10vh + $s-16); + gap: $s-4; + margin-left: $s-8; +} - &:hover { - background-color: var(--assets-item-background-color-hover); - .cell-name { - display: block; - color: var(--assets-item-name-foreground-color-hover); - background: linear-gradient(to top, rgba(52, 57, 59, 1) 0%, rgba(52, 57, 59, 0) 100%); - &.editing { - display: flex; - background: var(--input-background-color); - input { - color: var(--input-foreground-color-active); - } - span svg { - stroke: var(--input-foreground-color-active); - } - } - } - } - - &.selected { - border: $s-4 solid var(--assets-item-border-color); - } - } - .grid-placeholder { - width: 100%; - border-radius: $br-8; - background-color: var(--assets-item-background-color-drag); - border: $s-2 solid var(--assets-item-border-color-drag); - } +.grid-cell { + @include flexCenter; + position: relative; + padding: $s-8; + border: $s-4 solid transparent; + border-radius: $br-8; + background-color: var(--assets-component-background-color); + overflow: hidden; + cursor: pointer; + img { + height: auto; + width: auto; + max-height: 100%; + max-width: 100%; + pointer-events: none; } - .asset-enum { - margin: 0 $s-12; - .enum-item { - position: relative; + svg { + height: 10vh; + } + .cell-name { + @include titleTipography; + @include textEllipsis; + display: none; + position: absolute; + left: 0; + bottom: 0; + width: 100%; + padding: $s-2; + &.editing { display: flex; align-items: center; - height: $s-36; - margin-bottom: $s-4; - padding: $s-2; + height: $s-32; + border: $s-1 solid var(--input-border-color-focus); border-radius: $br-8; - background-color: var(--assets-item-background-color); - cursor: pointer; - - svg, - img { - @include flexCenter; - flex-shrink: 0; - padding: $s-2; - height: $s-32; - width: $s-32; - border-radius: $br-6; - background-color: var(--color-foreground-secondary); - } - - .item-name { - @include titleTipography; + background-color: var(--input-background-color); + input { @include textEllipsis; - padding-left: $s-8; - color: var(--assets-item-name-foreground-color); - &.editing { - display: flex; - align-items: center; - height: $s-32; - border: $s-1 solid var(--input-border-color-focus); - border-radius: $br-8; - background-color: var(--input-background-color); - input { - @include textEllipsis; - @include titleTipography; - @include removeInputStyle; - flex-grow: 1; - height: $s-28; - max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); - padding-left: $s-6; - margin: 0; - border-radius: $br-8; - color: var(--input-foreground-color); - } - span { - @include flexCenter; - height: $s-28; - background-color: transparent; - border-radius: $br-8; - svg { - @extend .button-icon-small; - stroke: var(--input-foreground-color); - transform: rotate(90deg); - } - } + @include titleTipography; + @include removeInputStyle; + flex-grow: 1; + height: $s-28; + max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); + padding-left: $s-6; + margin: 0; + border-radius: $br-8; + color: var(--input-foreground-color); + } + span { + @include flexCenter; + height: $s-28; + background-color: transparent; + border-radius: $br-8; + svg { + @extend .button-icon-small; + stroke: var(--input-foreground-color); + transform: rotate(90deg); } } - - &:hover { - background-color: var(--assets-item-background-color-hover); - .item-name { - color: var(--assets-item-name-foreground-color-hover); - &.editing { - background: var(--input-background-color); - input { - color: var(--input-foreground-color-active); - } - span svg { - stroke: var(--input-foreground-color-active); - } - } - } - } - &.selected { - border: $s-1 solid var(--assets-item-border-color); - } - } - .grid-placeholder { - height: $s-2; - width: 100%; - background-color: var(--color-accent-primary); } } + + &:hover { + background-color: var(--assets-item-background-color-hover); + .cell-name { + display: block; + color: var(--assets-item-name-foreground-color-hover); + background: linear-gradient(to top, rgba(52, 57, 59, 1) 0%, rgba(52, 57, 59, 0) 100%); + &.editing { + display: flex; + background: var(--input-background-color); + input { + color: var(--input-foreground-color-active); + } + span svg { + stroke: var(--input-foreground-color-active); + } + } + } + } + + &.selected { + border: $s-4 solid var(--assets-item-border-color); + } } + +.grid-placeholder { + width: 100%; + border-radius: $br-8; + background-color: var(--assets-item-background-color-drag); + border: $s-2 solid var(--assets-item-border-color-drag); +} + +.asset-enum { + margin: 0 $s-12; +} +.enum-item { + position: relative; + display: flex; + align-items: center; + height: $s-36; + margin-bottom: $s-4; + padding: $s-2; + border-radius: $br-8; + background-color: var(--assets-item-background-color); + cursor: pointer; + + svg, + img { + @include flexCenter; + flex-shrink: 0; + padding: $s-2; + height: $s-32; + width: $s-32; + border-radius: $br-6; + background-color: var(--color-foreground-secondary); + } + + .item-name { + @include titleTipography; + @include textEllipsis; + padding-left: $s-8; + color: var(--assets-item-name-foreground-color); + &.editing { + display: flex; + align-items: center; + height: $s-32; + border: $s-1 solid var(--input-border-color-focus); + border-radius: $br-8; + background-color: var(--input-background-color); + input { + @include textEllipsis; + @include titleTipography; + @include removeInputStyle; + flex-grow: 1; + height: $s-28; + max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); + padding-left: $s-6; + margin: 0; + border-radius: $br-8; + color: var(--input-foreground-color); + } + span { + @include flexCenter; + height: $s-28; + background-color: transparent; + border-radius: $br-8; + svg { + @extend .button-icon-small; + stroke: var(--input-foreground-color); + transform: rotate(90deg); + } + } + } + } + + &:hover { + background-color: var(--assets-item-background-color-hover); + .item-name { + color: var(--assets-item-name-foreground-color-hover); + &.editing { + background: var(--input-background-color); + input { + color: var(--input-foreground-color-active); + } + span svg { + stroke: var(--input-foreground-color-active); + } + } + } + } + &.selected { + border: $s-1 solid var(--assets-item-border-color); + } +} + +.grid-placeholder { + height: $s-2; + width: 100%; + background-color: var(--color-accent-primary); +} + .listing-options { display: flex; align-items: center; +} - .listing-option-btn { - @include flexCenter; - cursor: pointer; - background-color: var(--button-radio-background-color-rest); +.listing-option-btn { + @include flexCenter; + cursor: pointer; + background-color: var(--button-radio-background-color-rest); - &.first { - margin-left: auto; - } + &.first { + margin-left: auto; + } - svg { - @extend .button-icon; - } + svg { + @extend .button-icon; } } + .add-component { @extend .button-tertiary; height: $s-32; @@ -224,6 +228,7 @@ stroke: var(--icon-foreground); } } + :global(.three-row) { .asset-grid { grid-template-columns: repeat(3, 1fr); diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs index 116ebd2abb..4b584aea7a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.assets.file-library - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -40,62 +40,41 @@ (mf/defc file-library-title {::mf/wrap-props false} - [{:keys [open? local? shared? project-id file-id page-id file-name]}] + [{:keys [open? local? project-id file-id page-id file-name]}] (let [router (mf/deref refs/router) url (rt/resolve router :workspace {:project-id project-id :file-id file-id} {:page-id page-id}) - new-css-system (mf/use-ctx ctx/new-css-system) toggle-open (mf/use-fn (mf/deps file-id open?) (fn [] (st/emit! (dw/set-assets-section-open file-id :library (not open?)))))] - (if ^boolean new-css-system - [:div {:class (dom/classnames (css :library-title) true)} - [:& title-bar {:collapsable? true - :collapsed? (not open?) - :clickable-all? true - :on-collapsed toggle-open - :title (if local? - (mf/html [:div {:class (dom/classnames (css :special-title) true)} (tr "workspace.assets.local-library")]) + [:div {:class (stl/css :library-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :clickable-all? true + :on-collapsed toggle-open + :title (if local? + (mf/html [:div {:class (stl/css :special-title)} + (tr "workspace.assets.local-library")]) + ;; Do we need to add shared info here? - (mf/html [:div {:class (dom/classnames (css :special-title) true)} file-name]))} - (when-not local? - [:span.tool-link.tooltip.tooltip-left {:alt "Open library file"} - [:a {:class (dom/classnames (css :file-link) true) - :href (str "#" url) - :target "_blank" - :on-click dom/stop-propagation} - i/open-link-refactor]])]] - - [:div.tool-window-bar.library-bar - {:on-click toggle-open} - [:div.collapse-library - {:class (dom/classnames :open open?)} - i/arrow-slide] - - (if local? - [:* - [:span.library-title (tr "workspace.assets.local-library")] - (when shared? - [:span.shared-library {:alt (tr "workspace.assets.shared-library") :title (tr "workspace.assets.shared-library")} - i/library] - )] - [:* - [:span.library-title {:title file-name} file-name] - [:span.tool-link {:alt (tr "workspace.assets.open-library") :title (tr "workspace.assets.open-library")} - [:a {:href (str "#" url) - :target "_blank" - :on-click dom/stop-propagation} - i/chain]]])]))) + (mf/html [:div {:class (stl/css :special-title)} + file-name]))} + (when-not local? + [:span.tool-link.tooltip.tooltip-left {:alt "Open library file"} + [:a {:class (dom/classnames true) + :href (str "#" url) + :target "_blank" + :on-click dom/stop-propagation} + i/open-link-refactor]])]])) (mf/defc file-library-content {::mf/wrap-props false} [{:keys [file local? open-status-ref on-clear-selection]}] (let [components-v2 (mf/use-ctx ctx/components-v2) - new-css-system (mf/use-ctx ctx/new-css-system) open-status (mf/deref open-status-ref) file-id (:id file) @@ -111,9 +90,6 @@ reverse-sort? (= :desc filters-ordering) listing-thumbs? (= :thumbs filters-list-style) - toggle-ordering (mf/use-ctx cmm/assets-toggle-ordering) - toggle-list-style (mf/use-ctx cmm/assets-toggle-list-style) - library-ref (mf/with-memo [file-id] (create-file-library-ref file-id)) @@ -155,10 +131,6 @@ (l/derived lens:selected))) selected (mf/deref selected-lens) - selected-count (+ (count (get selected :components)) - (count (get selected :graphics)) - (count (get selected :colors)) - (count (get selected :typographies))) has-term? (not ^boolean (str/empty? filters-term)) force-open-components? (when ^boolean has-term? (> 60 (count components))) @@ -246,166 +218,80 @@ (st/emit! (dwu/commit-undo-transaction undo-id)))))] - (if ^boolean new-css-system - [:div {:class (dom/classnames (css :library-content) true)} - (when ^boolean show-components? - [:& components-section - {:file-id file-id - :local? local? - :components components - :listing-thumbs? listing-thumbs? - :open? (or ^boolean force-open-components? - ^boolean (get open-status :components false)) - :force-open? force-open-components? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-component-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) + [:div {:class (stl/css :library-content)} + (when ^boolean show-components? + [:& components-section + {:file-id file-id + :local? local? + :components components + :listing-thumbs? listing-thumbs? + :open? (or ^boolean force-open-components? + ^boolean (get open-status :components false)) + :force-open? force-open-components? + :open-status-ref open-status-ref + :reverse-sort? reverse-sort? + :selected selected + :on-asset-click on-component-click + :on-assets-delete on-assets-delete + :on-clear-selection on-clear-selection}]) - (when ^boolean show-graphics? - [:& graphics-section - {:file-id file-id - :project-id project-id - :local? local? - :objects media - :listing-thumbs? listing-thumbs? - :open? (or ^boolean force-open-graphics? - ^boolean (get open-status :graphics false)) - :force-open? force-open-graphics? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-graphics-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) + (when ^boolean show-graphics? + [:& graphics-section + {:file-id file-id + :project-id project-id + :local? local? + :objects media + :listing-thumbs? listing-thumbs? + :open? (or ^boolean force-open-graphics? + ^boolean (get open-status :graphics false)) + :force-open? force-open-graphics? + :open-status-ref open-status-ref + :reverse-sort? reverse-sort? + :selected selected + :on-asset-click on-graphics-click + :on-assets-delete on-assets-delete + :on-clear-selection on-clear-selection}]) - (when ^boolean show-colors? - [:& colors-section - {:file-id file-id - :local? local? - :colors colors - :open? (or ^boolean force-open-colors? - ^boolean (get open-status :colors false)) - :force-open? force-open-colors? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-colors-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) + (when ^boolean show-colors? + [:& colors-section + {:file-id file-id + :local? local? + :colors colors + :open? (or ^boolean force-open-colors? + ^boolean (get open-status :colors false)) + :force-open? force-open-colors? + :open-status-ref open-status-ref + :reverse-sort? reverse-sort? + :selected selected + :on-asset-click on-colors-click + :on-assets-delete on-assets-delete + :on-clear-selection on-clear-selection}]) - (when ^boolean show-typography? - [:& typographies-section - {:file file - :file-id (:id file) - :local? local? - :typographies typographies - :open? (or ^boolean force-open-typographies? - ^boolean (get open-status :typographies false)) - :force-open? force-open-typographies? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-typography-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) + (when ^boolean show-typography? + [:& typographies-section + {:file file + :file-id (:id file) + :local? local? + :typographies typographies + :open? (or ^boolean force-open-typographies? + ^boolean (get open-status :typographies false)) + :force-open? force-open-typographies? + :open-status-ref open-status-ref + :reverse-sort? reverse-sort? + :selected selected + :on-asset-click on-typography-click + :on-assets-delete on-assets-delete + :on-clear-selection on-clear-selection}]) - (when (and (not ^boolean show-components?) - (not ^boolean show-graphics?) - (not ^boolean show-colors?) - (not ^boolean show-typography?)) - [:div {:class (css :asset-title)} - [:span {:class (css :no-found-icon)} - i/search-refactor] - [:span {:class (css :no-found-text)} - (tr "workspace.assets.not-found")]])] - [:div.tool-window-content - [:div.listing-options - (when (> selected-count 0) - [:span.selected-count - (tr "workspace.assets.selected-count" (i18n/c selected-count))]) - [:div.listing-option-btn.first {:on-click toggle-ordering} - (if reverse-sort? - i/sort-ascending - i/sort-descending)] - [:div.listing-option-btn {:on-click toggle-list-style} - (if listing-thumbs? - i/listing-enum - i/listing-thumbs)]] - - (when ^boolean show-components? - [:& components-section - {:file-id file-id - :local? local? - :components components - :listing-thumbs? listing-thumbs? - :open? (or ^boolean force-open-components? - ^boolean (get open-status :components false)) - :force-open? force-open-components? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-component-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) - - (when ^boolean show-graphics? - [:& graphics-section - {:file-id file-id - :project-id project-id - :local? local? - :objects media - :listing-thumbs? listing-thumbs? - :open? (or ^boolean force-open-graphics? - ^boolean (get open-status :graphics false)) - :force-open? force-open-graphics? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-graphics-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) - - (when ^boolean show-colors? - [:& colors-section - {:file-id file-id - :local? local? - :colors colors - :open? (or ^boolean force-open-colors? - ^boolean (get open-status :colors false)) - :force-open? force-open-colors? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-colors-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) - - (when ^boolean show-typography? - [:& typographies-section - {:file file - :file-id (:id file) - :local? local? - :typographies typographies - :open? (or ^boolean force-open-typographies? - ^boolean (get open-status :typographies false)) - :force-open? force-open-typographies? - :open-status-ref open-status-ref - :reverse-sort? reverse-sort? - :selected selected - :on-asset-click on-typography-click - :on-assets-delete on-assets-delete - :on-clear-selection on-clear-selection}]) - - (when (and (not ^boolean show-components?) - (not ^boolean show-graphics?) - (not ^boolean show-colors?) - (not ^boolean show-typography?)) - [:div.asset-section - [:div.asset-title - (tr "workspace.assets.not-found")]])]))) + (when (and (not ^boolean show-components?) + (not ^boolean show-graphics?) + (not ^boolean show-colors?) + (not ^boolean show-typography?)) + [:div {:class (stl/css :asset-title)} + [:span {:class (stl/css :no-found-icon)} + i/search-refactor] + [:span {:class (stl/css :no-found-text)} + (tr "workspace.assets.not-found")]])])) (mf/defc file-library @@ -416,7 +302,6 @@ shared? (:is-shared file) project-id (:project-id file) page-id (dm/get-in file [:data :pages 0]) - new-css-system (mf/use-ctx ctx/new-css-system) open-status-ref (mf/with-memo [file-id] (-> (l/key file-id) @@ -429,8 +314,7 @@ (mf/deps file-id) (fn [] (st/emit! (dw/unselect-all-assets file-id))))] - [:div {:class (dom/classnames (css :tool-window) new-css-system - :tool-window (not new-css-system)) + [:div {:class (stl/css :tool-window) :on-context-menu dom/prevent-default :on-click unselect-all} [:& file-library-title diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.scss index 68b50d27c0..0044dbcd18 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.scss @@ -8,35 +8,35 @@ .tool-window { margin-bottom: $s-24; } -.library-title { - .file-name { - @include titleTipography; - display: flex; - justify-content: flex-start; - align-items: center; - flex-grow: 100; - height: 100%; - } - .special-title { - @include textEllipsis; - color: var(--title-foreground-color-hover); - margin-left: $s-2; - text-align: left; - } +.file-name { + @include titleTipography; + display: flex; + justify-content: flex-start; + align-items: center; + flex-grow: 100; + height: 100%; +} - .file-link { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - border-radius: $br-8; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - fill: var(--title-foreground-color-hover); - } +.special-title { + @include textEllipsis; + color: var(--title-foreground-color-hover); + margin-left: $s-2; + text-align: left; +} + +.file-link { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + border-radius: $br-8; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + fill: var(--title-foreground-color-hover); } } + .library-content { display: flex; flex-direction: column; @@ -53,22 +53,23 @@ flex-direction: column; align-items: center; gap: $s-8; - .no-found-icon { - @include flexCenter; - background-color: var(--not-found-background-color); - border-radius: $br-circle; - height: $s-48; - width: $s-48; - svg { - @extend .button-icon; - height: $s-24; - width: $s-24; - stroke: var(--not-found-foreground-color); - } - } +} - .no-found-text { - @include titleTipography; - color: var(--not-found-foreground-color); +.no-found-icon { + @include flexCenter; + background-color: var(--not-found-background-color); + border-radius: $br-circle; + height: $s-48; + width: $s-48; + svg { + @extend .button-icon; + height: $s-24; + width: $s-24; + stroke: var(--not-found-foreground-color); } } + +.no-found-text { + @include titleTipography; + color: var(--not-found-foreground-color); +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs index 0dd0b0b47e..2705c891cb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs @@ -14,7 +14,6 @@ [app.main.store :as st] [app.main.ui.components.forms :as fm] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.assets.common :as cmm] [app.util.dom :as dom] @@ -27,7 +26,6 @@ (when-not (empty? path) (let [[other-path last-path truncated] (cfh/compact-path path 35 true) menu-state (mf/use-state cmm/initial-context-menu-state) - new-css-system (mf/use-ctx ctx/new-css-system) on-fold-group (mf/use-fn (mf/deps file-id section path group-open?) @@ -46,45 +44,28 @@ on-close-menu (mf/use-fn #(swap! menu-state cmm/close-context-menu))] - (if new-css-system - [:div {:class (stl/css :group-title) - :on-context-menu on-context-menu} - [:& title-bar {:collapsable? true - :collapsed? (not group-open?) - :clickable-all? true - :on-collapsed on-fold-group - :title (mf/html [:* (when-not (empty? other-path) - [:span {:class (stl/css :pre-path) - :title (when truncated path)} - other-path "\u00A0\u2022\u00A0"]) - [:span {:class (stl/css :path) - :title (when truncated path)} - last-path]])}] - [:& cmm/assets-context-menu - {:on-close on-close-menu - :state @menu-state - :options [{:option-name (tr "workspace.assets.rename") - :id "assets-rename-group" - :option-handler #(on-rename % path last-path)} - {:option-name (tr "workspace.assets.ungroup") - :id "assets-ungroup-group" - :option-handler #(on-ungroup path)}]}]] - - - [:div.group-title {:class (when-not group-open? "closed") - :on-click on-fold-group - :on-context-menu on-context-menu} - [:span i/arrow-slide] - (when-not (empty? other-path) - [:span.dim {:title (when truncated path)} - other-path "\u00A0/\u00A0"]) - [:span {:title (when truncated path)} - last-path] - [:& cmm/assets-context-menu - {:on-close on-close-menu - :state @menu-state - :options [[(tr "workspace.assets.rename") #(on-rename % path last-path)] - [(tr "workspace.assets.ungroup") #(on-ungroup path)]]}]])))) + [:div {:class (stl/css :group-title) + :on-context-menu on-context-menu} + [:& title-bar {:collapsable? true + :collapsed? (not group-open?) + :clickable-all? true + :on-collapsed on-fold-group + :title (mf/html [:* (when-not (empty? other-path) + [:span {:class (stl/css :pre-path) + :title (when truncated path)} + other-path "\u00A0\u2022\u00A0"]) + [:span {:class (stl/css :path) + :title (when truncated path)} + last-path]])}] + [:& cmm/assets-context-menu + {:on-close on-close-menu + :state @menu-state + :options [{:option-name (tr "workspace.assets.rename") + :id "assets-rename-group" + :option-handler #(on-rename % path last-path)} + {:option-name (tr "workspace.assets.ungroup") + :id "assets-ungroup-group" + :option-handler #(on-ungroup path)}]}]]))) (defn group-assets "Convert a list of assets in a nested structure like this: @@ -120,8 +101,7 @@ ::mf/register-as :name-group-dialog} [{:keys [path last-path accept] :as ctx :or {path "" last-path ""}}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - initial (mf/use-memo + (let [initial (mf/use-memo (mf/deps last-path) (constantly {:asset-name last-path})) form (fm/use-form :spec ::name-group-form @@ -142,69 +122,36 @@ (accept asset-name) (accept path asset-name)) (modal/hide!))))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} - (if create? - (tr "workspace.assets.create-group") - (tr "workspace.assets.rename-group"))] - [:button {:class (stl/css :modal-close-btn) - :on-click on-close} i/close-refactor]] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} + (if create? + (tr "workspace.assets.create-group") + (tr "workspace.assets.rename-group"))] + [:button {:class (stl/css :modal-close-btn) + :on-click on-close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:& fm/form {:form form :on-submit on-accept} - [:& fm/input {:name :asset-name - :class (stl/css :input-wrapper) - :auto-focus? true - :label (tr "workspace.assets.group-name") - :hint (tr "workspace.assets.create-group-hint")}]]] + [:div {:class (stl/css :modal-content)} + [:& fm/form {:form form :on-submit on-accept} + [:& fm/input {:name :asset-name + :class (stl/css :input-wrapper) + :auto-focus? true + :label (tr "workspace.assets.group-name") + :hint (tr "workspace.assets.create-group-hint")}]]] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:input - {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.cancel") - :on-click on-close}] + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:input + {:class (stl/css :cancel-button) + :type "button" + :value (tr "labels.cancel") + :on-click on-close}] - [:input - {:type "button" - :class (stl/css-case :accept-btn true - :global/disabled (not (:valid @form) )) - :disabled (not (:valid @form)) - :value (if create? (tr "labels.create") (tr "labels.rename")) - :on-click on-accept}]]]]] - - - [:div.modal-overlay - [:div.modal-container.confirm-dialog - [:div.modal-header - [:div.modal-header-title - [:h2 (if create? - (tr "workspace.assets.create-group") - (tr "workspace.assets.rename-group"))]] - [:div.modal-close-button - {:on-click on-close} i/close]] - - [:div.modal-content.generic-form - [:& fm/form {:form form :on-submit on-accept} - [:& fm/input {:name :asset-name - :auto-focus? true - :label (tr "workspace.assets.group-name") - :hint (tr "workspace.assets.create-group-hint")}]]] - - [:div.modal-footer - [:div.action-buttons - [:input.cancel-button - {:type "button" - :value (tr "labels.cancel") - :on-click on-close}] - - [:input.accept-button.primary - {:type "button" - :class (when-not (:valid @form) "btn-disabled") - :disabled (not (:valid @form)) - :value (if create? (tr "labels.create") (tr "labels.rename")) - :on-click on-accept}]]]]]))) + [:input + {:type "button" + :class (stl/css-case :accept-btn true + :global/disabled (not (:valid @form))) + :disabled (not (:valid @form)) + :value (if create? (tr "labels.create") (tr "labels.rename")) + :on-click on-accept}]]]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.scss index 93235d3bae..c3091a7cb2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.scss @@ -8,52 +8,57 @@ .group-title { padding-left: $s-4; - .pre-path { - margin-left: $s-2; - text-transform: initial; - color: var(--title-foreground-color); - } - .path { - margin-left: $s-2; - text-transform: initial; - color: var(--title-foreground-color-hover); - } +} + +.pre-path { + margin-left: $s-2; + text-transform: initial; + color: var(--title-foreground-color); +} + +.path { + margin-left: $s-2; + text-transform: initial; + color: var(--title-foreground-color-hover); } .modal-overlay { @extend .modal-overlay-base; - .modal-container { - @extend .modal-container-base; - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } - .modal-content { - @include titleTipography; - margin-bottom: $s-24; - .input-wrapper { - @extend .input-with-label; - } - } - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-btn { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } - } +} + +.modal-container { + @extend .modal-container-base; +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + margin-bottom: $s-24; +} +.input-wrapper { + @extend .input-with-label; +} +.action-buttons { + @extend .modal-action-btns; +} +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs index 5708709d33..d85b1979cb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs @@ -46,7 +46,6 @@ dragging? (deref dragging*) read-only? (mf/use-ctx ctx/workspace-read-only?) - new-css-system (mf/use-ctx ctx/new-css-system) editing? (= editing-id (:id typography)) renaming? (= renaming-id (:id typography)) @@ -100,52 +99,29 @@ (mf/deps typography apply-typography on-asset-click) (partial on-asset-click typography-id apply-typography))] - (if ^boolean new-css-system - [:div {:class (stl/css :typography-item) - :ref item-ref - :draggable (and (not read-only?) (not open?)) - :on-drag-start on-typography-drag-start - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} + [:div {:class (stl/css :typography-item) + :ref item-ref + :draggable (and (not read-only?) (not open?)) + :on-drag-start on-typography-drag-start + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} - [:& typography-entry - {:typography typography - :local? local? - :on-context-menu on-context-menu - :on-change handle-change - :selected? (contains? selected typography-id) - :on-click on-asset-click - :editing? editing? - :renaming? renaming? - :focus-name? rename? - :external-open* open* - :file-id file-id}] - (when ^boolean dragging? - [:div {:class (stl/css :dragging)}])] - - [:div.typography-container {:ref item-ref - :draggable (and (not read-only?) (not open?)) - :on-drag-start on-typography-drag-start - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - [:& typography-entry - {:typography typography - :local? local? - :on-context-menu on-context-menu - :on-change handle-change - :selected? (contains? selected typography-id) - :on-click on-asset-click - :editing? editing? - :focus-name? rename? - :external-open* open* - :file-id file-id}] - - (when ^boolean dragging? - [:div.dragging])]))) + [:& typography-entry + {:typography typography + :local? local? + :on-context-menu on-context-menu + :on-change handle-change + :selected? (contains? selected typography-id) + :on-click on-asset-click + :editing? editing? + :renaming? renaming? + :focus-name? rename? + :external-open* open* + :file-id file-id}] + (when ^boolean dragging? + [:div {:class (stl/css :dragging)}])])) (mf/defc typographies-group {::mf/wrap-props false} @@ -155,7 +131,6 @@ (let [group-open? (get open-groups prefix true) dragging* (mf/use-state false) dragging? (deref dragging*) - new-css-system (mf/use-ctx ctx/new-css-system) selected-paths (mf/with-memo [selected-full] (into #{} (comp (map :path) (d/nilv "")) @@ -183,134 +158,72 @@ (fn [event] (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full move-typography)))] - (if ^boolean new-css-system - [:div {:class (stl/css :typographies-group) - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - [:& grp/asset-group-title {:file-id file-id - :section :typographies - :path prefix - :group-open? group-open? - :on-rename on-rename-group - :on-ungroup on-ungroup}] + [:div {:class (stl/css :typographies-group) + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} + [:& grp/asset-group-title {:file-id file-id + :section :typographies + :path prefix + :group-open? group-open? + :on-rename on-rename-group + :on-ungroup on-ungroup}] - (when group-open? - [:* - (let [typographies (get groups "" [])] - [:div {:class (stl/css :assets-list) - :on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} + (when group-open? + [:* + (let [typographies (get groups "" [])] + [:div {:class (stl/css :assets-list) + :on-drag-enter on-drag-enter + :on-drag-leave on-drag-leave + :on-drag-over dom/prevent-default + :on-drop on-drop} - (when ^boolean dragging? - [:div {:class (stl/css :grid-placeholder)} "\u00A0"]) + (when ^boolean dragging? + [:div {:class (stl/css :grid-placeholder)} "\u00A0"]) - (when (and - (empty? typographies) - (some? groups)) - [:div {:class (stl/css :drop-space)}]) - (for [{:keys [id] :as typography} typographies] - [:& typography-item {:typography typography - :key (dm/str "typography-" id) - :file-id file-id + (when (and + (empty? typographies) + (some? groups)) + [:div {:class (stl/css :drop-space)}]) + (for [{:keys [id] :as typography} typographies] + [:& typography-item {:typography typography + :key (dm/str "typography-" id) + :file-id file-id + :local? local? + :handle-change handle-change + :selected selected + :apply-typography apply-typography + :editing-id editing-id + :renaming-id renaming-id + :rename? (= (:rename-typography local-data) id) + :on-asset-click on-asset-click + :on-context-menu on-context-menu + :selected-full selected-full + :selected-paths selected-paths + :move-typography move-typography}])]) + + (for [[path-item content] groups] + (when-not (empty? path-item) + [:& typographies-group {:file-id file-id + :prefix (cfh/merge-path-item prefix path-item) + :key (dm/str "group-" path-item) + :groups content + :open-groups open-groups + :force-open? force-open? + :file file :local? local? - :handle-change handle-change :selected selected - :apply-typography apply-typography :editing-id editing-id :renaming-id renaming-id - :rename? (= (:rename-typography local-data) id) + :local-data local-data :on-asset-click on-asset-click - :on-context-menu on-context-menu - :selected-full selected-full - :selected-paths selected-paths - :move-typography move-typography}])]) - - (for [[path-item content] groups] - (when-not (empty? path-item) - [:& typographies-group {:file-id file-id - :prefix (cfh/merge-path-item prefix path-item) - :key (dm/str "group-" path-item) - :groups content - :open-groups open-groups - :force-open? force-open? - :file file - :local? local? - :selected selected - :editing-id editing-id - :renaming-id renaming-id - :local-data local-data - :on-asset-click on-asset-click - :handle-change handle-change - :apply-typography apply-typography - :on-rename-group on-rename-group - :on-ungroup on-ungroup - :on-context-menu on-context-menu - :selected-full selected-full}]))])] - [:div {:on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - [:& grp/asset-group-title {:file-id file-id - :section :typographies - :path prefix - :group-open? group-open? - :on-rename on-rename-group - :on-ungroup on-ungroup}] - (when group-open? - [:* - (let [typographies (get groups "" [])] - [:div.asset-list {:on-drag-enter on-drag-enter - :on-drag-leave on-drag-leave - :on-drag-over dom/prevent-default - :on-drop on-drop} - - (when ^boolean dragging? - [:div.grid-placeholder "\u00A0"]) - - (when (and - (empty? typographies) - (some? groups)) - [:div.drop-space]) - (for [{:keys [id] :as typography} typographies] - [:& typography-item {:typography typography - :key (dm/str "typography-" id) - :file-id file-id - :local? local? :handle-change handle-change - :selected selected :apply-typography apply-typography - :editing-id editing-id - :rename? (= (:rename-typography local-data) id) - :on-asset-click on-asset-click + :on-rename-group on-rename-group + :on-ungroup on-ungroup :on-context-menu on-context-menu - :selected-full selected-full - :selected-paths selected-paths - :move-typography move-typography}])]) - - (for [[path-item content] groups] - (when-not (empty? path-item) - [:& typographies-group {:file-id file-id - :prefix (cfh/merge-path-item prefix path-item) - :key (dm/str "group-" path-item) - :groups content - :open-groups open-groups - :force-open? force-open? - :file file - :local? local? - :selected selected - :editing-id editing-id - :local-data local-data - :on-asset-click on-asset-click - :handle-change handle-change - :apply-typography apply-typography - :on-rename-group on-rename-group - :on-ungroup on-ungroup - :on-context-menu on-context-menu - :selected-full selected-full}]))])]))) + :selected-full selected-full}]))])])) (mf/defc typographies-section {::mf/wrap-props false} @@ -320,7 +233,6 @@ local-data (mf/deref lens:typography-section-state) read-only? (mf/use-ctx ctx/workspace-read-only?) - new-css-system (mf/use-ctx ctx/new-css-system) menu-state (mf/use-state cmm/initial-context-menu-state) typographies (mf/with-memo [typographies] (mapv dwl/extract-path-if-missing typographies)) @@ -465,10 +377,7 @@ (dwl/sync-file file-id file-id :typographies (:id @state)) (dwu/commit-undo-transaction undo-id)))))) - editing-id (if new-css-system - (:edit-typography local-data) - (or (:rename-typography local-data) - (:edit-typography local-data))) + editing-id (:edit-typography local-data) renaming-id (:rename-typography local-data) @@ -478,10 +387,8 @@ (partial on-asset-click groups))] (mf/use-effect - (mf/deps local-data new-css-system) + (mf/deps local-data ) (fn [] - (when (and (not new-css-system)(:rename-typography local-data)) - (st/emit! #(update % :workspace-global dissoc :rename-typography))) (when (:edit-typography local-data) (st/emit! #(update % :workspace-global dissoc :edit-typography))))) @@ -491,19 +398,12 @@ :section :typographies :assets-count (count typographies) :open? open?} - (if ^boolean new-css-system - (when local? - [:& cmm/asset-section-block {:role :title-button} - (when-not read-only? - [:button {:class (stl/css :assets-btn) - :on-click add-typography} - i/add-refactor])]) - - (when local? - [:& cmm/asset-section-block {:role :title-button} - (when-not read-only? - [:div.assets-button {:on-click add-typography} - i/plus])])) + (when local? + [:& cmm/asset-section-block {:role :title-button} + (when-not read-only? + [:button {:class (stl/css :assets-btn) + :on-click add-typography} + i/add-refactor])]) [:& cmm/asset-section-block {:role :content} [:& typographies-group {:file-id file-id @@ -530,38 +430,28 @@ [:& cmm/assets-context-menu {:on-close on-close-menu :state @menu-state - :options (if new-css-system - [(when-not (or multi-typographies? multi-assets?) - {:option-name (tr "workspace.assets.rename") - :id "assets-rename-typography" - :option-handler handle-rename-typography-clicked}) - - (when-not (or multi-typographies? multi-assets?) - {:option-name (tr "workspace.assets.edit") - :id "assets-edit-typography" - :option-handler handle-edit-typography-clicked}) - - {:option-name (tr "workspace.assets.delete") - :id "assets-delete-typography" - :option-handler handle-delete-typography} - - (when-not multi-assets? - {:option-name (tr "workspace.assets.group") - :id "assets-group-typography" - :option-handler on-group})] - - [(when-not (or multi-typographies? multi-assets?) - [(tr "workspace.assets.rename") handle-rename-typography-clicked]) - (when-not (or multi-typographies? multi-assets?) - [(tr "workspace.assets.edit") handle-edit-typography-clicked]) - [(tr "workspace.assets.delete") handle-delete-typography] - (when-not multi-assets? - [(tr "workspace.assets.group") on-group])])}] - - (when new-css-system - [:& cmm/assets-context-menu - {:on-close on-close-menu - :state @menu-state - :options [{:option-name "show info" + :options [(when-not (or multi-typographies? multi-assets?) + {:option-name (tr "workspace.assets.rename") :id "assets-rename-typography" - :option-handler handle-edit-typography-clicked}]}]))]]])) + :option-handler handle-rename-typography-clicked}) + + (when-not (or multi-typographies? multi-assets?) + {:option-name (tr "workspace.assets.edit") + :id "assets-edit-typography" + :option-handler handle-edit-typography-clicked}) + + {:option-name (tr "workspace.assets.delete") + :id "assets-delete-typography" + :option-handler handle-delete-typography} + + (when-not multi-assets? + {:option-name (tr "workspace.assets.group") + :id "assets-group-typography" + :option-handler on-group})]}] + + [:& cmm/assets-context-menu + {:on-close on-close-menu + :state @menu-state + :options [{:option-name "show info" + :id "assets-rename-typography" + :option-handler handle-edit-typography-clicked}]}])]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss index 01a0bb172d..e0ad31a23a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss @@ -17,34 +17,37 @@ stroke: var(--icon-foreground); } } -.typographies-group { - .assets-list { - padding: 0 0 0 $s-4; - .drop-space { - height: $s-12; - } - .grid-placeholder { - height: $s-2; - width: 100%; - background-color: var(--color-accent-primary); - } - .typography-item { - position: relative; - display: flex; - align-items: center; - margin-bottom: $s-4; - border-radius: $br-8; - background-color: var(--assets-item-background-color); - } - .dragging { - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 100%; - border: $s-2 solid var(--assets-item-border-color-drag); - border-radius: $s-8; - background-color: var(--assets-item-background-color-drag); - } - } + +.assets-list { + padding: 0 0 0 $s-4; +} + +.drop-space { + height: $s-12; +} + +.grid-placeholder { + height: $s-2; + width: 100%; + background-color: var(--color-accent-primary); +} + +.typography-item { + position: relative; + display: flex; + align-items: center; + margin-bottom: $s-4; + border-radius: $br-8; + background-color: var(--assets-item-background-color); +} + +.dragging { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + border: $s-2 solid var(--assets-item-border-color-drag); + border-radius: $s-8; + background-color: var(--assets-item-background-color-drag); } From 0a123a39178caecbc4d9d14799079491feded469 Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 2 Jan 2024 11:15:02 +0100 Subject: [PATCH 08/35] :recycle: Remove refer css from files --- .../app/main/ui/components/search_bar.cljs | 10 +- .../app/main/ui/components/search_bar.scss | 93 +++---- .../app/main/ui/workspace/context_menu.cljs | 80 ++---- .../app/main/ui/workspace/context_menu.scss | 158 ++++++------ .../workspace/sidebar/collapsable_button.cljs | 28 +-- .../main/ui/workspace/sidebar/history.cljs | 176 +++++--------- .../main/ui/workspace/sidebar/history.scss | 226 ++++++++--------- .../main/ui/workspace/sidebar/shortcuts.cljs | 230 +++++------------- 8 files changed, 401 insertions(+), 600 deletions(-) diff --git a/frontend/src/app/main/ui/components/search_bar.cljs b/frontend/src/app/main/ui/components/search_bar.cljs index 507b68d1e7..705bb3b4d7 100644 --- a/frontend/src/app/main/ui/components/search_bar.cljs +++ b/frontend/src/app/main/ui/components/search_bar.cljs @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.components.search-bar - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -45,16 +45,16 @@ node (dom/get-target event)] (when ^boolean enter? (dom/blur! node)) (when ^boolean esc? (dom/blur! node)))))] - [:span {:class (dom/classnames (css :search-box) true - (css :has-children) (some? children))} + [:span {:class (stl/css-case :search-box true + :has-children (some? children))} children - [:div {:class (dom/classnames (css :search-input-wrapper) true)} + [:div {:class (stl/css :search-input-wrapper)} icon [:input {:on-change handle-change :value value :placeholder placeholder :on-key-down handle-key-down}] (when (not= "" value) - [:button {:class (dom/classnames (css :clear) true) + [:button {:class (stl/css :clear) :on-click handle-clear} i/delete-text-refactor])]])) diff --git a/frontend/src/app/main/ui/components/search_bar.scss b/frontend/src/app/main/ui/components/search_bar.scss index 9f568ea286..850b8af221 100644 --- a/frontend/src/app/main/ui/components/search_bar.scss +++ b/frontend/src/app/main/ui/components/search_bar.scss @@ -13,55 +13,56 @@ width: 100%; border-radius: $br-8; background-color: var(--search-bar-background-color); +} - .search-input-wrapper { - @include flexCenter; - height: $s-32; +.search-input-wrapper { + @include flexCenter; + height: $s-32; + width: 100%; + border: $s-1 solid var(--search-bar-input-border-color); + border-radius: $br-8; + background-color: var(--search-bar-input-background-color); + input { width: 100%; - border: $s-1 solid var(--search-bar-input-border-color); - border-radius: $br-8; - background-color: var(--search-bar-input-background-color); - input { - width: 100%; - height: 100%; - margin: 0 $s-8 0 $s-4; - border: 0; - background-color: var(--input-background-color); - font-size: $fs-12; - color: var(--input-foreground-color); - &:focus { - outline: none; - } - } - &:hover { - border: $s-1 solid var(--input-background-color-hover); - background-color: var(--input-background-color-hover); - input { - background-color: var(--input-background-color-hover); - } - } - &:focus-within { - background-color: var(--input-background-color-active); - color: var(--input-foreground-color-active); - border: $s-1 solid var(--input-border-color-focus); - input { - background-color: var(--input-background-color-active); - } - } - - .clear { - @extend .button-tag; - border-radius: $br-8; - height: 100%; - svg { - @extend .button-icon-small; - color: transparent; - stroke: var(--icon-foreground); - } + height: 100%; + margin: 0 $s-8 0 $s-4; + border: 0; + background-color: var(--input-background-color); + font-size: $fs-12; + color: var(--input-foreground-color); + &:focus { + outline: none; } } - &.has-children .search-input-wrapper { - border-radius: $br-2 $br-8 $br-8 $br-2; - margin-left: 0; + &:hover { + border: $s-1 solid var(--input-background-color-hover); + background-color: var(--input-background-color-hover); + input { + background-color: var(--input-background-color-hover); + } + } + &:focus-within { + background-color: var(--input-background-color-active); + color: var(--input-foreground-color-active); + border: $s-1 solid var(--input-border-color-focus); + input { + background-color: var(--input-background-color-active); + } } } + +.clear { + @extend .button-tag; + border-radius: $br-8; + height: 100%; + svg { + @extend .button-icon-small; + color: transparent; + stroke: var(--icon-foreground); + } +} + +.search-box.has-children .search-input-wrapper { + border-radius: $br-2 $br-8 $br-8 $br-2; + margin-left: 0; +} diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 3312782eac..e8140696aa 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -6,7 +6,7 @@ (ns app.main.ui.workspace.context-menu "A workspace specific context menu (mouse right click)." - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -31,7 +31,6 @@ [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.shape-icon-refactor :as sic] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.assets.common :as cmm] [app.util.dom :as dom] @@ -52,7 +51,6 @@ [{:keys [title shortcut on-click on-pointer-enter on-pointer-leave on-unmount children selected? icon disabled] :as props}] (let [submenu-ref (mf/use-ref nil) hovering? (mf/use-ref false) - new-css-system (mf/use-ctx ctx/new-css-system) on-pointer-enter (mf/use-callback (fn [] @@ -86,71 +84,44 @@ (constantly on-unmount)) (if icon - [:li {:class (if new-css-system - (dom/classnames (css :icon-menu-item) true) - (dom/classnames :icon-menu-item true)) + [:li {:class (stl/css :icon-menu-item) :disabled disabled :ref set-dom-node :on-click on-click :on-pointer-enter on-pointer-enter :on-pointer-leave on-pointer-leave} [:span - {:class (if new-css-system - (dom/classnames (css :icon-wrapper) true) - (dom/classnames :icon-wrapper true))} - (if selected? [:span {:class (if new-css-system - (dom/classnames (css :selected-icon) true) - (dom/classnames :selected-icon true))} - (if new-css-system - i/tick-refactor - i/tick)] - [:span {:class (if new-css-system - (dom/classnames (css :selected-icon) true) - (dom/classnames :selected-icon true))}]) - [:span {:class (if new-css-system - (dom/classnames (css :shape-icon) true) - (dom/classnames :shape-icon true))} icon]] - [:span {:class (if new-css-system - (dom/classnames (css :title) true) - (dom/classnames :title true))} title]] - [:li {:class (dom/classnames (css :context-menu-item) new-css-system) + {:class (stl/css :icon-wrapper)} + (if selected? [:span {:class (stl/css :selected-icon)} + i/tick-refactor] + [:span {:class (stl/css :selected-icon)}]) + [:span {:class (stl/css :shape-icon)} icon]] + [:span {:class (stl/css :title)} title]] + [:li {:class (stl/css :context-menu-item) :disabled disabled :ref set-dom-node :on-click on-click :on-pointer-enter on-pointer-enter :on-pointer-leave on-pointer-leave} - [:span {:class (if new-css-system - (dom/classnames (css :title) true) - (dom/classnames :title true))} title] + [:span {:class (stl/css :title)} title] (when shortcut - [:span {:class (if new-css-system - (dom/classnames (css :shortcut) true) - (dom/classnames :shortcut true))} - (if new-css-system - (for [sc (scd/split-sc shortcut)] - [:span {:class (dom/classnames (css :shortcut-key) true)} sc]) - (or shortcut ""))]) + [:span {:class (stl/css :shortcut)} + (for [sc (scd/split-sc shortcut)] + [:span {:class (stl/css :shortcut-key)} sc])]) (when (> (count children) 1) - (if new-css-system - [:span {:class (dom/classnames (css :submenu-icon) true)} i/arrow-refactor] - [:span.submenu-icon i/arrow-slide])) + [:span {:class (stl/css :submenu-icon)} i/arrow-refactor]) (when (> (count children) 1) - [:ul - {:class (if new-css-system - (dom/classnames (css :workspace-context-submenu) true) - (dom/classnames :workspace-context-menu true)) - :ref submenu-ref - :style {:display "none" :left 250} - :on-context-menu prevent-default} + [:ul {:class (stl/css :workspace-context-submenu) + :ref submenu-ref + :style {:display "none" :left 250} + :on-context-menu prevent-default} children])]))) + (mf/defc menu-separator [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - [:li {:class (if new-css-system - (dom/classnames (css :separator) true) - (dom/classnames :separator true))}])) + [:li {:class (stl/css :separator)}]) (mf/defc context-menu-edit [_] @@ -482,8 +453,8 @@ [:* [:& menu-separator] [:& menu-entry {:title (tr "workspace.shape.menu.delete") - :shortcut (sc/get-tooltip :delete) - :on-click do-delete}]])) + :shortcut (sc/get-tooltip :delete) + :on-click do-delete}]])) (mf/defc shape-context-menu {::mf/wrap [mf/memo]} @@ -632,8 +603,7 @@ (let [mdata (mf/deref menu-ref) top (- (get-in mdata [:position :y]) 20) left (get-in mdata [:position :x]) - dropdown-ref (mf/use-ref) - new-css-system (mf/use-ctx ctx/new-css-system)] + dropdown-ref (mf/use-ref)] (mf/use-effect (mf/deps mdata) @@ -651,9 +621,7 @@ [:& dropdown {:show (boolean mdata) :on-close #(st/emit! dw/hide-context-menu)} [:ul - {:class (if new-css-system - (dom/classnames (css :workspace-context-menu) true) - (dom/classnames :workspace-context-menu true)) + {:class (stl/css :workspace-context-menu) :ref dropdown-ref :style {:top top :left left} :on-context-menu prevent-default} diff --git a/frontend/src/app/main/ui/workspace/context_menu.scss b/frontend/src/app/main/ui/workspace/context_menu.scss index 23250aa093..4a178c88f8 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.scss +++ b/frontend/src/app/main/ui/workspace/context_menu.scss @@ -19,95 +19,97 @@ border-radius: $br-8; background-color: var(--menu-background-color); z-index: $z-index-3; - .separator { - height: $s-12; - } - .context-menu-item { - display: flex; - align-items: center; - justify-content: space-between; - height: $s-28; - width: 100%; - padding: $s-6; - border-radius: $br-8; - cursor: pointer; +} - .title { +.separator { + height: $s-12; +} + +.context-menu-item { + display: flex; + align-items: center; + justify-content: space-between; + height: $s-28; + width: 100%; + padding: $s-6; + border-radius: $br-8; + cursor: pointer; + + .title { + @include titleTipography; + color: var(--menu-foreground-color); + } + .shortcut { + @include flexCenter; + gap: $s-2; + color: var(--menu-shortcut-foreground-color); + .shortcut-key { @include titleTipography; - color: var(--menu-foreground-color); + @include flexCenter; + height: $s-20; + padding: $s-2 $s-6; + border-radius: $br-6; + background-color: var(--menu-shortcut-background-color); + } + } + + .submenu-icon { + position: absolute; + right: $s-16; + svg { + @extend .button-icon-small; + stroke: var(--menu-foreground-color); + } + } + &:hover { + background-color: var(--menu-background-color-hover); + .title { + color: var(--menu-foreground-color-hover); } .shortcut { - @include flexCenter; - gap: $s-2; - color: var(--menu-shortcut-foreground-color); - .shortcut-key { - @include titleTipography; - @include flexCenter; - height: $s-20; - padding: $s-2 $s-6; - border-radius: $br-6; - background-color: var(--menu-shortcut-background-color); - } + color: var(--menu-shortcut-foreground-color-hover); } + } + &:focus { + border: 1px solid var(--menu-border-color-focus); + background-color: var(--menu-background-color-focus); + } +} - .submenu-icon { - position: absolute; - right: $s-16; - svg { - @extend .button-icon-small; - stroke: var(--menu-foreground-color); - } - } - &:hover { - background-color: var(--menu-background-color-hover); - .title { - color: var(--menu-foreground-color-hover); - } - .shortcut { - color: var(--menu-shortcut-foreground-color-hover); - } - } - &:focus { - border: 1px solid var(--menu-border-color-focus); - background-color: var(--menu-background-color-focus); +.icon-menu-item { + display: flex; + justify-content: flex-start; + align-items: center; + height: $s-28; + padding: $s-6; + border-radius: $br-8; + &:hover { + background-color: var(--menu-background-color-hover); + } + + span.title { + margin-left: $s-6; + } + + .selected-icon { + svg { + @extend .button-icon-small; + stroke: var(--menu-foreground-color); } } - .icon-menu-item { - display: flex; - justify-content: flex-start; - align-items: center; - height: $s-28; - padding: $s-6; - border-radius: $br-8; - &:hover { - background-color: var(--menu-background-color-hover); + .shape-icon { + margin-left: $s-2; + svg { + @extend .button-icon-small; + stroke: var(--menu-foreground-color); } + } - span.title { - margin-left: $s-6; - } - - .selected-icon { - svg { - @extend .button-icon-small; - stroke: var(--menu-foreground-color); - } - } - - .shape-icon { - margin-left: $s-2; - svg { - @extend .button-icon-small; - stroke: var(--menu-foreground-color); - } - } - - .icon-wrapper { - display: grid; - grid-template-columns: 1fr 1fr; - margin: 0; - } + .icon-wrapper { + display: grid; + grid-template-columns: 1fr 1fr; + margin: 0; } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs index f292e9ad4c..643114f07f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs @@ -5,31 +5,23 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.collapsable-button - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.main.data.workspace :as dw] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.util.dom :as dom] [app.util.i18n :refer [tr]] [rumext.v2 :as mf])) (mf/defc collapsed-button {::mf/wrap-props false} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-click (mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))] - (if ^boolean new-css-system - [:div {:id "left-sidebar-aside" - :data-size 0 - :class (dom/classnames (css :collapsed-sidebar) true)} - [:div {:class (dom/classnames (css :collapsed-title) true)} - [:button {:class (dom/classnames (css :collapsed-button) true) - :on-click on-click - :aria-label (tr "workspace.sidebar.expand")} - i/arrow-refactor]]] - [:button.collapse-sidebar.collapsed - {:on-click on-click - :aria-label (tr "workspace.sidebar.expand")} - i/arrow-slide]))) + (let [on-click (mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))] + [:div {:id "left-sidebar-aside" + :data-size 0 + :class (stl/css :collapsed-sidebar)} + [:div {:class (stl/css :collapsed-title)} + [:button {:class (stl/css :collapsed-button) + :on-click on-click + :aria-label (tr "workspace.sidebar.expand")} + i/arrow-refactor]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.cljs b/frontend/src/app/main/ui/workspace/sidebar/history.cljs index 67cb6075d8..c4fb5650ea 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/history.cljs @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.history - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.main.data.events :as ev] @@ -13,9 +13,7 @@ [app.main.data.workspace.common :as dwc] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.util.dom :as dom] [app.util.i18n :refer [t] :as i18n] [cuerdas.core :as str] [okulary.core :as l] @@ -277,103 +275,57 @@ (mf/defc history-entry-details [{:keys [entry]}] (let [{entries :items} (mf/deref workspace-undo) - new-css-system (mf/use-ctx ctx/new-css-system) objects (mf/deref refs/workspace-page-objects)] - (if new-css-system - [:div {:class (css :history-entry-detail)} - (case (:operation entry) - :new - (:name (get-object (:detail entry) entries objects)) + [:div {:class (stl/css :history-entry-detail)} + (case (:operation entry) + :new + (:name (get-object (:detail entry) entries objects)) - :delete - [:ul {:class (css :ul.history-entry-details-list)} - (for [id (:detail entry)] - (let [shape-name (:name (get-object id entries objects))] - [:li {:key id} shape-name]))] + :delete + [:ul {:class (stl/css :history-entry-details-list)} + (for [id (:detail entry)] + (let [shape-name (:name (get-object id entries objects))] + [:li {:key id} shape-name]))] - :modify - [:ul {:class (css :ul.history-entry-details-list)} - (for [[id attributes] (:detail entry)] - (let [shape-name (:name (get-object id entries objects))] - [:li {:key id} - [:div shape-name] - [:div (str/join ", " attributes)]]))] + :modify + [:ul {:class (stl/css :history-entry-details-list)} + (for [[id attributes] (:detail entry)] + (let [shape-name (:name (get-object id entries objects))] + [:li {:key id} + [:div shape-name] + [:div (str/join ", " attributes)]]))] - nil)] - - [:div.history-entry-detail - (case (:operation entry) - :new - (:name (get-object (:detail entry) entries objects)) - - :delete - [:ul.history-entry-details-list - (for [id (:detail entry)] - (let [shape-name (:name (get-object id entries objects))] - [:li {:key id} shape-name]))] - - - :modify - [:ul.history-entry-details-list - (for [[id attributes] (:detail entry)] - (let [shape-name (:name (get-object id entries objects))] - [:li {:key id} - [:div shape-name] - [:div (str/join ", " attributes)]]))] - - nil)] - ))) + nil)])) (mf/defc history-entry [{:keys [locale entry idx-entry disabled? current?]}] (let [hover? (mf/use-state false) - new-css-system (mf/use-ctx ctx/new-css-system) show-detail? (mf/use-state false)] - (if new-css-system - [:div {:class (dom/classnames (css :history-entry) true - (css :disabled) disabled? - (css :current) current? - (css :hover) @hover? - (css :show-detail) @show-detail?) - :on-pointer-enter #(reset! hover? true) - :on-pointer-leave #(reset! hover? false) - :on-click #(st/emit! (dwc/undo-to-index idx-entry))} - [:div {:class (dom/classnames (css :history-entry-summary) true)} - [:div {:class (dom/classnames (css :history-entry-summary-icon) true)} (entry->icon-refactor entry)] - [:div {:class (dom/classnames (css :history-entry-summary-text) true)} (entry->message locale entry)] - (when (:detail entry) - [:div {:class (dom/classnames (css :history-entry-summary-button) true - (css :button-opened) @show-detail?) - :on-click #(when (:detail entry) - (swap! show-detail? not))} - i/arrow-refactor])] + [:div {:class (stl/css-case :history-entry true + :disabled disabled? + :current current? + :hover @hover? + :show-detail @show-detail?) + :on-pointer-enter #(reset! hover? true) + :on-pointer-leave #(reset! hover? false) + :on-click #(st/emit! (dwc/undo-to-index idx-entry))} + [:div {:class (stl/css :history-entry-summary)} + [:div {:class (stl/css :history-entry-summary-icon)} + (entry->icon-refactor entry)] + [:div {:class (stl/css :history-entry-summary-text)} (entry->message locale entry)] + (when (:detail entry) + [:div {:class (stl/css-case :history-entry-summary-button true + :button-opened @show-detail?) + :on-click #(when (:detail entry) + (swap! show-detail? not))} + i/arrow-refactor])] - (when @show-detail? - [:& history-entry-details {:entry entry}])] - - [:div.history-entry {:class (dom/classnames - :disabled disabled? - :current current? - :hover @hover? - :show-detail @show-detail?) - :on-pointer-enter #(reset! hover? true) - :on-pointer-leave #(reset! hover? false) - :on-click #(st/emit! (dwc/undo-to-index idx-entry))} - [:div.history-entry-summary - [:div.history-entry-summary-icon (entry->icon entry)] - [:div.history-entry-summary-text (entry->message locale entry)] - (when (:detail entry) - [:div.history-entry-summary-button {:on-click #(when (:detail entry) - (swap! show-detail? not))} - i/arrow-slide])] - - (when show-detail? - [:& history-entry-details {:entry entry}])]))) + (when @show-detail? + [:& history-entry-details {:entry entry}])])) (mf/defc history-toolbox [] (let [locale (mf/deref i18n/locale) - new-css-system (mf/use-ctx ctx/new-css-system) objects (mf/deref refs/workspace-page-objects) {:keys [items index]} (mf/deref workspace-undo) entries (parse-entries items objects) @@ -381,40 +333,24 @@ (mf/use-fn #(st/emit! (-> (dw/toggle-layout-flag :document-history) (vary-meta assoc ::ev/origin "history-toolbox"))))] - (if new-css-system - [:div {:class (css :history-toolbox)} - [:div {:class (css :history-toolbox-title)} - [:span (t locale "workspace.undo.title")] - [:div {:class (css :close-button) - :on-click toggle-history} - i/close-refactor]] - (if (empty? entries) - [:div {:class (css :history-entry-empty)} - [:div {:class (css :history-entry-empty-icon)} i/history-refactor] - [:div {:class (css :history-entry-empty-msg)} (t locale "workspace.undo.empty")]] - [:ul {:class (css :history-entries)} - (for [[idx-entry entry] (->> entries (map-indexed vector) reverse)] #_[i (range 0 10)] - [:& history-entry {:key (str "entry-" idx-entry) - :locale locale - :entry entry - :idx-entry idx-entry - :current? (= idx-entry index) - :disabled? (> idx-entry index)}])])] - - [:div.history-toolbox - [:div.history-toolbox-title (t locale "workspace.undo.title")] - (if (empty? entries) - [:div.history-entry-empty - [:div.history-entry-empty-icon i/recent] - [:div.history-entry-empty-msg (t locale "workspace.undo.empty")]] - [:ul.history-entries - (for [[idx-entry entry] (->> entries (map-indexed vector) reverse)] #_[i (range 0 10)] - [:& history-entry {:key (str "entry-" idx-entry) - :locale locale - :entry entry - :idx-entry idx-entry - :current? (= idx-entry index) - :disabled? (> idx-entry index)}])])]))) + [:div {:class (stl/css :history-toolbox)} + [:div {:class (stl/css :history-toolbox-title)} + [:span (t locale "workspace.undo.title")] + [:div {:class (stl/css :close-button) + :on-click toggle-history} + i/close-refactor]] + (if (empty? entries) + [:div {:class (stl/css :history-entry-empty)} + [:div {:class (stl/css :history-entry-empty-icon)} i/history-refactor] + [:div {:class (stl/css :history-entry-empty-msg)} (t locale "workspace.undo.empty")]] + [:ul {:class (stl/css :history-entries)} + (for [[idx-entry entry] (->> entries (map-indexed vector) reverse)] #_[i (range 0 10)] + [:& history-entry {:key (str "entry-" idx-entry) + :locale locale + :entry entry + :idx-entry idx-entry + :current? (= idx-entry index) + :disabled? (> idx-entry index)}])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.scss b/frontend/src/app/main/ui/workspace/sidebar/history.scss index 1870531c2f..9a23cda6cc 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/history.scss @@ -10,138 +10,138 @@ display: flex; flex-direction: column; background-color: var(--panel-background-color); +} - .history-toolbox-title { +.history-toolbox-title { + @include flexCenter; + @include tabTitleTipography; + position: relative; + height: $s-32; + min-height: $s-32; + margin: $s-8 $s-8 0 $s-8; + border-radius: $br-8; + background-color: var(--panel-title-background-color); + + span { @include flexCenter; - @include tabTitleTipography; - position: relative; - height: $s-32; - min-height: $s-32; - margin: $s-8 $s-8 0 $s-8; - border-radius: $br-8; - background-color: var(--panel-title-background-color); + flex-grow: 1; + color: var(--title-foreground-color-hover); + } +} - span { - @include flexCenter; - flex-grow: 1; - color: var(--title-foreground-color-hover); - } +.close-button { + @extend .button-tertiary; + position: absolute; + right: $s-2; + top: $s-2; + height: $s-28; + width: $s-28; + border-radius: $br-6; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} - .close-button { - @extend .button-tertiary; - position: absolute; - right: $s-2; - top: $s-2; - height: $s-28; - width: $s-28; - border-radius: $br-6; +.history-entry-empty { + @include flexCenter; + flex-direction: column; + gap: $s-16; + padding: $s-28 $s-16; + text-align: center; +} + +.history-entry-empty-icon { + @extend .empty-icon; + svg { + margin-left: calc(-1 * $s-2); + } +} + +.history-entry-empty-msg { + @include titleTipography; + color: var(--title-foreground-secondary); +} + +.history-entries { + height: 100%; + padding: $s-12; + overflow-x: hidden; + overflow-y: auto; + font-size: $fs-12; +} + +.history-entry { + display: flex; + justify-content: center; + flex-direction: column; + min-height: $s-32; + margin: $s-4; + padding: $s-4 $s-8; + border: $s-2 solid transparent; + border-radius: $s-8; + background-color: var(--entry-background-color); + cursor: pointer; + transition: border 0.2s; + + .history-entry-summary { + display: flex; + align-items: center; + .history-entry-summary-icon { svg { - @extend .button-icon; - stroke: var(--icon-foreground); + @extend .button-icon-small; + stroke: var(--entry-foreground-color); + } + } + .history-entry-summary-text { + margin: 0 $s-8; + } + .history-entry-summary-button { + opacity: $op-0; + margin-left: auto; + &.button-opened { + svg { + transform: rotate(90deg); + } + } + svg { + @extend .button-icon-small; + stroke: var(--entry-foreground-color); } } } - .history-entry-empty { - @include flexCenter; - flex-direction: column; - gap: $s-16; - padding: $s-28 $s-16; - text-align: center; + .history-entry-detail { + display: block; + padding-top: $s-16; - .history-entry-empty-icon { - @extend .empty-icon; - svg { - margin-left: calc(-1 * $s-2); - } - } - - .history-entry-empty-msg { - @include titleTipography; - color: var(--title-foreground-secondary); + .history-entry-details-list { + margin: 0; } } - ul.history-entries { - height: 100%; - padding: $s-12; - overflow-x: hidden; - overflow-y: auto; - font-size: $fs-12; + &.disabled { + border-color: var(--entry-border-color-disabled); + background-color: var(--entry-background-color-disabled); + } - .history-entry { - display: flex; - justify-content: center; - flex-direction: column; - min-height: $s-32; - margin: $s-4; - padding: $s-4 $s-8; - border: $s-2 solid transparent; - border-radius: $s-8; - background-color: var(--entry-background-color); - cursor: pointer; - transition: border 0.2s; - - &.disabled { - border-color: var(--entry-border-color-disabled); - background-color: var(--entry-background-color-disabled); - } - - &.hover, - &:hover { - background-color: var(--entry-background-color-hover); - color: var(--entry-foreground-color-hover); - .history-entry-summary { - .history-entry-summary-icon { - svg { - stroke: var(--entry-foreground-color-hover); - } - } - .history-entry-summary-button { - opacity: $op-10; - &.button-opened { - svg { - transform: rotate(90deg); - } - } - } + &.hover, + &:hover { + background-color: var(--entry-background-color-hover); + color: var(--entry-foreground-color-hover); + .history-entry-summary { + .history-entry-summary-icon { + svg { + stroke: var(--entry-foreground-color-hover); } } - - .history-entry-summary { - display: flex; - align-items: center; - .history-entry-summary-icon { + .history-entry-summary-button { + opacity: $op-10; + &.button-opened { svg { - @extend .button-icon-small; - stroke: var(--entry-foreground-color); + transform: rotate(90deg); } } - .history-entry-summary-text { - margin: 0 $s-8; - } - .history-entry-summary-button { - opacity: $op-0; - margin-left: auto; - &.button-opened { - svg { - transform: rotate(90deg); - } - } - svg { - @extend .button-icon-small; - stroke: var(--entry-foreground-color); - } - } - } - - .history-entry-detail { - display: block; - padding-top: $s-16; - - ul.history-entry-details-list { - margin: 0; - } } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs index 65b37b1e10..04748ef406 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs @@ -5,13 +5,12 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.shortcuts - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] [app.config :as cf] [app.main.data.dashboard.shortcuts] - [app.main.data.events :as ev] [app.main.data.shortcuts :as ds] [app.main.data.viewer.shortcuts] [app.main.data.workspace :as dw] @@ -19,21 +18,17 @@ [app.main.data.workspace.shortcuts] [app.main.store :as st] [app.main.ui.components.search-bar :refer [search-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :refer [tr]] - [app.util.keyboard :as kbd] [app.util.strings :refer [matches-search]] [clojure.set :as set] [clojure.string] - [cuerdas.core :as str] [rumext.v2 :as mf])) (mf/defc converted-chars [{:keys [char command] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - modified-keys {:up ds/up-arrow + (let [modified-keys {:up ds/up-arrow :down ds/down-arrow :left ds/left-arrow :right ds/right-arrow @@ -51,10 +46,8 @@ char (if (contains? modified-keys (keyword char)) ((keyword char) modified-keys) char) char (if (and is-macos? (contains? macos-keys (keyword char))) ((keyword char) macos-keys) char) unique-key (str (d/name command) "-" char)] - (if new-css-system - [:span {:class (css :key) - :key unique-key} char] - [:span.char-box {:key unique-key} char]))) + [:span {:class (stl/css :key) + :key unique-key} char])) (defn translation-keyname [type keyname] @@ -222,8 +215,7 @@ (mf/defc shortcuts-keys [{:keys [content command] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - managed-list (if (coll? content) + (let [managed-list (if (coll? content) content (conj () content)) chars-list (map ds/split-sc managed-list) @@ -232,43 +224,25 @@ chars-list (drop-last chars-list)) penultimate (last short-char-list)] - (if new-css-system - [:span {:class (css :keys)} - (for [chars short-char-list] - [:* - (for [char chars] - [:& converted-chars {:key (dm/str char "-" (name command)) - :char char - :command command}]) - (when (not= chars penultimate) [:span {:class (css :space)} ","])]) - (when (not= last-element penultimate) - [:* - [:span {:class (css :space)} (tr "shortcuts.or")] - (for [char last-element] - [:& converted-chars {:key (dm/str char "-" (name command)) - :char char - :command command}])])] - - [:span.keys - (for [chars short-char-list] - [:* - (for [char chars] - [:& converted-chars {:key (dm/str char "-" (name command)) - :char char - :command command}]) - (when (not= chars penultimate) [:span.space ","])]) - (when (not= last-element penultimate) - [:* - [:span.space (tr "shortcuts.or")] - (for [char last-element] - [:& converted-chars {:key (dm/str char "-" (name command)) - :char char - :command command}])])]))) + [:span {:class (stl/css :keys)} + (for [chars short-char-list] + [:* + (for [char chars] + [:& converted-chars {:key (dm/str char "-" (name command)) + :char char + :command command}]) + (when (not= chars penultimate) [:span {:class (stl/css :space)} ","])]) + (when (not= last-element penultimate) + [:* + [:span {:class (stl/css :space)} (tr "shortcuts.or")] + (for [char last-element] + [:& converted-chars {:key (dm/str char "-" (name command)) + :char char + :command command}])])])) (mf/defc shortcut-row [{:keys [elements filter-term match-section? match-subsection?] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - shortcut-name (keys elements) + (let [shortcut-name (keys elements) shortcut-translations (map #(translation-keyname :sc %) shortcut-name) match-shortcut? (some #(matches-search % @filter-term) shortcut-translations) filtered (if (and (or match-section? match-subsection?) (not match-shortcut?)) @@ -276,46 +250,32 @@ (filter #(matches-search % @filter-term) shortcut-translations)) sorted-filtered (sort filtered)] - (if new-css-system - [:ul {:class (css :sub-menu)} - (for [command-translate sorted-filtered] - (let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements)) - [command comand-info] sc-by-translate - content (or (:show-command comand-info) (:command comand-info))] - [:li {:class (css :shortcuts-name) - :key command-translate} - [:span {:class (css :command-name)} - command-translate] - [:& shortcuts-keys {:content content - :command command}]]))] - - [:ul.sub-menu - (for [command-translate sorted-filtered] - (let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements)) - [command comand-info] sc-by-translate - content (or (:show-command comand-info) (:command comand-info))] - [:li.shortcut-name {:key command-translate} - [:span.command-name command-translate] - [:& shortcuts-keys {:content content - :command command}]]))]))) + [:ul {:class (stl/css :sub-menu)} + (for [command-translate sorted-filtered] + (let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements)) + [command comand-info] sc-by-translate + content (or (:show-command comand-info) (:command comand-info))] + [:li {:class (stl/css :shortcuts-name) + :key command-translate} + [:span {:class (stl/css :command-name)} + command-translate] + [:& shortcuts-keys {:content content + :command command}]]))])) (mf/defc section-title [{:keys [is-visible? name is-sub?] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (if is-sub? (css :subsection-title) (css :section-title))} - [:span {:class (dom/classnames (css :open) is-visible? - (css :collapsed-shortcuts) true)} i/arrow-refactor] - [:span {:class (if is-sub? (css :subsection-name) (css :section-name))} name]] - - [:div {:class (if is-sub? "subsection-title" "section-title")} - [:span.collapesed-shortcuts {:class (when is-visible? "open")} i/arrow-slide] - [:span {:class (if is-sub? "subsection-name" "section-name")} name]]))) + [:div {:class (if is-sub? + (stl/css :subsection-title) + (stl/css :section-title))} + [:span {:class (stl/css-case :open is-visible? + :collapsed-shortcuts true)} i/arrow-refactor] + [:span {:class (if is-sub? + (stl/css :subsection-name) + (stl/css :section-name))} name]]) (mf/defc shortcut-subsection [{:keys [subsections manage-sections filter-term match-section? open-sections] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - subsections-names (keys subsections) + (let [subsections-names (keys subsections) subsection-translations (if (= :none (first subsections-names)) (map #(translation-keyname :sc %) subsections-names) (map #(translation-keyname :sub-sec %) subsections-names)) @@ -328,8 +288,7 @@ :match-section? match-section? :match-subsection? true}]) - [:ul {:class (dom/classnames (css :subsection-menu) new-css-system - :subsection-menu (not new-css-system))} + [:ul {:class (stl/css :subsection-menu)} (for [sub-translated sorted-translations] (let [sub-by-translate (first (filter #(= (:translation (second %)) sub-translated) subsections)) [sub-name sub-info] sub-by-translate @@ -368,7 +327,7 @@ visible? (some #(= % section-id) @open-sections)] (when (or match-section? match-subsection? match-shortcut?) - [:div {:class (css :section) + [:div {:class (stl/css :section) :on-click (manage-sections section-id)} [:& section-title {:is-visible? visible? :is-sub? false @@ -383,8 +342,7 @@ (mf/defc shortcuts-container [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - workspace-shortcuts app.main.data.workspace.shortcuts/shortcuts + (let [workspace-shortcuts app.main.data.workspace.shortcuts/shortcuts path-shortcuts app.main.data.workspace.path.shortcuts/shortcuts all-workspace-shortcuts (->> (d/deep-merge path-shortcuts workspace-shortcuts) (add-translation :sc) @@ -496,13 +454,6 @@ (manage-section-on-search :viewer term))] (reset! open-sections ids)))) - on-search-term-change - (mf/use-callback - (fn [event] - (let [value (dom/get-target-val event)] - (manage-sections-on-search value) - (reset! filter-term value)))) - on-search-term-change-2 (mf/use-callback (fn [value] @@ -512,80 +463,31 @@ (mf/use-callback (fn [_] (reset! open-sections [[1]]) - (reset! filter-term ""))) - - manage-key-down - (mf/use-callback - (fn [event] - (when (kbd/esc? event) - (st/emit! (-> (dw/toggle-layout-flag :shortcuts) - (vary-meta assoc ::ev/origin "shortcuts-panel")))))) - - on-key-down - (mf/use-callback - (fn [event] - (when (kbd/enter? event) - (on-search-clear-click) - (dom/focus! (dom/get-element "shortcut-search")))))] + (reset! filter-term "")))] (mf/with-effect [] (dom/focus! (dom/get-element "shortcut-search"))) - (if new-css-system - [:div {:class (css :shortcuts)} - [:div {:class (css :shortcuts-header)} - [:div {:class (css :shortcuts-title)} (tr "shortcuts.title")] - [:div {:class (css :shortcuts-close-button) - :on-click close-fn} - i/close-refactor]] - [:div {:class (css :search-field)} + [:div {:class (stl/css :shortcuts)} + [:div {:class (stl/css :shortcuts-header)} + [:div {:class (stl/css :shortcuts-title)} (tr "shortcuts.title")] + [:div {:class (stl/css :shortcuts-close-button) + :on-click close-fn} + i/close-refactor]] + [:div {:class (stl/css :search-field)} - [:& search-bar {:on-change on-search-term-change-2 - :clear-action on-search-clear-click - :value @filter-term - :placeholder (tr "shortcuts.title") - :icon (mf/html [:span {:class (css :search-icon)} i/search-refactor])}]] + [:& search-bar {:on-change on-search-term-change-2 + :clear-action on-search-clear-click + :value @filter-term + :placeholder (tr "shortcuts.title") + :icon (mf/html [:span {:class (stl/css :search-icon)} i/search-refactor])}]] - (if match-any? - [:div {:class (dom/classnames (css :shortcuts-list) true)} - (for [section all-shortcuts] - [:& shortcut-section - {:section section - :manage-sections manage-sections - :open-sections open-sections - :filter-term filter-term}])] - [:div {:class (css :not-found)} (tr "shortcuts.not-found")])] - - [:div.shortcuts - [:div.shortcuts-header - [:div.shortcuts-close-button - {:on-click close-fn} i/close] - [:div.shortcuts-title (tr "shortcuts.title")]] - [:div.search-field - [:div.search-box - [:input.input-text - {:id "shortcut-search" - :placeholder (tr "shortcuts.search-placeholder") - :type "text" - :value @filter-term - :on-change on-search-term-change - :auto-complete "off" - :on-key-down manage-key-down}] - (if (str/empty? @filter-term) - [:span.icon-wrapper - i/search] - [:button.icon-wrapper - {:on-click on-search-clear-click - :on-key-down on-key-down} - [:span.icon.close - i/close]])]] - (if match-any? - [:div.shortcut-list - (for [section all-shortcuts] - [:& shortcut-section - {:section section - :manage-sections manage-sections - :open-sections open-sections - :filter-term filter-term}])] - - [:div.not-found (tr "shortcuts.not-found")])]))) + (if match-any? + [:div {:class (stl/css :shortcuts-list)} + (for [section all-shortcuts] + [:& shortcut-section + {:section section + :manage-sections manage-sections + :open-sections open-sections + :filter-term filter-term}])] + [:div {:class (stl/css :not-found)} (tr "shortcuts.not-found")])])) From 67c692fdbdb28dbecb1510d8ce4e262f7ad39913 Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 2 Jan 2024 14:35:46 +0100 Subject: [PATCH 09/35] :recycle: Remove new-css-system from design tab --- .../src/app/main/ui/workspace/sidebar.cljs | 13 +- .../main/ui/workspace/sidebar/options.cljs | 194 +- .../main/ui/workspace/sidebar/options.scss | 40 +- .../ui/workspace/sidebar/options/common.cljs | 18 +- .../sidebar/options/menus/align.cljs | 184 +- .../sidebar/options/menus/align.scss | 45 +- .../workspace/sidebar/options/menus/blur.cljs | 123 +- .../workspace/sidebar/options/menus/blur.scss | 163 +- .../workspace/sidebar/options/menus/bool.cljs | 151 +- .../workspace/sidebar/options/menus/bool.scss | 55 +- .../options/menus/color_selection.cljs | 95 +- .../options/menus/color_selection.scss | 53 +- .../sidebar/options/menus/component.cljs | 3 - .../sidebar/options/menus/constraints.cljs | 243 +-- .../sidebar/options/menus/constraints.scss | 285 +-- .../sidebar/options/menus/exports.cljs | 191 +- .../sidebar/options/menus/exports.scss | 132 +- .../workspace/sidebar/options/menus/fill.cljs | 117 +- .../workspace/sidebar/options/menus/fill.scss | 94 +- .../sidebar/options/menus/frame_grid.cljs | 420 ++-- .../sidebar/options/menus/frame_grid.scss | 451 ++--- .../sidebar/options/menus/grid_cell.cljs | 312 +-- .../sidebar/options/menus/grid_cell.scss | 72 +- .../sidebar/options/menus/interactions.cljs | 1103 ++++------- .../sidebar/options/menus/layer.cljs | 125 +- .../sidebar/options/menus/layer.scss | 74 +- .../options/menus/layout_container.cljs | 1690 +++++------------ .../options/menus/layout_container.scss | 5 +- .../sidebar/options/menus/layout_item.cljs | 677 +++---- .../sidebar/options/menus/layout_item.scss | 231 +-- .../sidebar/options/menus/measures.cljs | 535 ++---- .../sidebar/options/menus/measures.scss | 405 ++-- .../sidebar/options/menus/shadow.cljs | 322 +--- .../sidebar/options/menus/shadow.scss | 228 ++- .../sidebar/options/menus/stroke.cljs | 143 +- .../sidebar/options/menus/stroke.scss | 79 +- .../sidebar/options/menus/svg_attrs.cljs | 108 +- .../sidebar/options/menus/svg_attrs.scss | 78 +- .../workspace/sidebar/options/menus/text.cljs | 439 ++--- .../workspace/sidebar/options/menus/text.scss | 116 +- .../sidebar/options/menus/typography.cljs | 668 ++----- .../sidebar/options/menus/typography.scss | 181 +- 42 files changed, 3852 insertions(+), 6809 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index e0433a1762..27511a6d44 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -158,7 +158,6 @@ ::mf/wrap [mf/memo]} [{:keys [layout section file page-id ] :as props}] (let [drawing-tool (:tool (mf/deref refs/workspace-drawing)) - new-css-system (mf/use-ctx ctx/new-css-system) is-comments? (= drawing-tool :comments) is-history? (contains? layout :document-history) @@ -195,10 +194,7 @@ (obj/set! "on-change-section" handle-change-section) (obj/set! "on-expand" handle-expand))] - [:aside {:class (stl/css-case new-css-system - :global/settings-bar (not new-css-system) - :global/settings-bar-right (not new-css-system) - :right-settings-bar true + [:aside {:class (stl/css-case :right-settings-bar true :not-expand (not can-be-expanded?) :expanded (> size 276)) @@ -206,14 +202,13 @@ :data-size size :style #js {"--width" (when can-be-expanded? (dm/str size "px"))}} (when can-be-expanded? - [:div {:class (stl/css new-css-system :resize-area) + [:div {:class (stl/css :resize-area) :on-pointer-down on-pointer-down :on-lost-pointer-capture on-lost-pointer-capture :on-pointer-move on-pointer-move}]) - (when new-css-system - [:& right-header {:file file :layout layout :page-id page-id}]) + [:& right-header {:file file :layout layout :page-id page-id}] - [:div {:class (stl/css new-css-system :settings-bar-inside)} + [:div {:class (stl/css :settings-bar-inside)} (cond (true? is-comments?) [:& comments-sidebar] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 76886baa48..763adb7fbb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -16,7 +16,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.tab-container :refer [tab-container tab-element]] - [app.main.ui.components.tabs-container :refer [tabs-container tabs-element]] [app.main.ui.context :as ctx] [app.main.ui.viewer.inspect.right-sidebar :as hrs] [app.main.ui.workspace.sidebar.options.menus.align :refer [align-options]] @@ -78,8 +77,7 @@ (mf/defc options-content {::mf/wrap [mf/memo]} [{:keys [selected section shapes shapes-with-children page-id file-id on-change-section on-expand]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - drawing (mf/deref refs/workspace-drawing) + (let [drawing (mf/deref refs/workspace-drawing) objects (mf/deref refs/workspace-page-objects) shared-libs (mf/deref refs/workspace-libraries) edition (mf/deref refs/selected-edition) @@ -100,144 +98,74 @@ (if (= options-mode :inspect) (st/emit! :interrupt (udw/set-workspace-read-only true)) (st/emit! :interrupt (udw/set-workspace-read-only false))))] - (if ^boolean new-css-system - [:div {:class (stl/css :tool-window)} - [:& tab-container - {:on-change-tab on-change-tab - :selected section - :collapsable? false - :content-class (stl/css :content-class) - :class (stl/css :tab-spacing)} - [:& tab-element {:id :design - :title (tr "workspace.options.design")} - [:div {:class (stl/css :element-options)} - [:& align-options] - [:& bool-options] - (cond - (and edit-grid? (d/not-empty? selected-cells)) - [:& grid-cell/options - {:shape (get objects edition) - :cells selected-cells}] + [:div {:class (stl/css :tool-window)} + [:& tab-container + {:on-change-tab on-change-tab + :selected section + :collapsable? false + :content-class (stl/css :content-class) + :class (stl/css :tab-spacing)} + [:& tab-element {:id :design + :title (tr "workspace.options.design")} + [:div {:class (stl/css :element-options)} + [:& align-options] + [:& bool-options] - edit-grid? - [:& layout-container/grid-layout-edition - {:ids [edition] - :values (get objects edition)}] + (cond + (and edit-grid? (d/not-empty? selected-cells)) + [:& grid-cell/options + {:shape (get objects edition) + :cells selected-cells}] - (not (nil? sp-panel)) - [:& specialized-panel {:panel sp-panel}] + edit-grid? + [:& layout-container/grid-layout-edition + {:ids [edition] + :values (get objects edition)}] - (d/not-empty? drawing) - [:& shape-options - {:shape (:object drawing) - :page-id page-id - :file-id file-id - :shared-libs shared-libs}] + (not (nil? sp-panel)) + [:& specialized-panel {:panel sp-panel}] - (= 0 (count selected)) - [:& page/options] + (d/not-empty? drawing) + [:& shape-options + {:shape (:object drawing) + :page-id page-id + :file-id file-id + :shared-libs shared-libs}] - (= 1 (count selected)) - [:& shape-options - {:shape (first selected-shapes) - :page-id page-id - :file-id file-id - :shared-libs shared-libs - :shapes-with-children shapes-with-children}] + (= 0 (count selected)) + [:& page/options] - :else - [:& multiple/options - {:shapes-with-children shapes-with-children - :shapes selected-shapes - :page-id page-id - :file-id file-id - :shared-libs shared-libs}])]] - [:& tab-element {:id :prototype - :title (tr "workspace.options.prototype")} - [:div {:class (stl/css :element-options)} - [:& interactions-menu {:shape (first shapes)}]]] - [:& tab-element {:id :inspect - :title (tr "workspace.options.inspect")} - [:div {:class (stl/css :element-options)} - [:& hrs/right-sidebar {:page-id page-id - :objects objects - :file-id file-id - :frame shape-parent-frame - :shapes selected-shapes - :on-change-section on-change-section - :on-expand on-expand - :from :workspace}]]]]] + (= 1 (count selected)) + [:& shape-options + {:shape (first selected-shapes) + :page-id page-id + :file-id file-id + :shared-libs shared-libs + :shapes-with-children shapes-with-children}] - [:div.tool-window - [:div.tool-window-content - [:& tabs-container {:on-change-tab on-change-tab - :selected section} - [:& tabs-element {:id :design - :title (tr "workspace.options.design")} - [:div.element-options - [:& align-options] - [:& bool-options] - (cond - (d/not-empty? selected-cells) - [:& grid-cell/options - {:shape (get objects edition) - :cells selected-cells}] - - edit-grid? - [:& layout-container/grid-layout-edition - {:ids [edition] - :values (get objects edition)}] - - sp-panel - [:& specialized-panel {:panel sp-panel}] - - - (d/not-empty? drawing) - [:& shape-options - {:shape (:object drawing) - :page-id page-id - :file-id file-id - :shared-libs shared-libs}] - - (= 0 (count selected)) - [:& page/options] - - (= 1 (count selected)) - [:& shape-options - {:shape (first selected-shapes) - :page-id page-id - :file-id file-id - :shared-libs shared-libs - :shapes-with-children shapes-with-children}] - - :else - [:& multiple/options - {:shapes-with-children shapes-with-children - :shapes selected-shapes - :page-id page-id - :file-id file-id - :shared-libs shared-libs}])]] - - [:& tabs-element - {:id :prototype - :title (tr "workspace.options.prototype")} - - [:div.element-options - [:& interactions-menu {:shape (first shapes)}]]] - - [:& tabs-element {:id :inspect - :title (tr "workspace.options.inspect")} - - [:div.element-options.element-options-inspect - [:& hrs/right-sidebar {:page-id page-id - :objects objects - :file-id file-id - :frame shape-parent-frame - :shapes selected-shapes - :on-change-section on-change-section - :on-expand on-expand - :from :workspace}]]]]]]))) + :else + [:& multiple/options + {:shapes-with-children shapes-with-children + :shapes selected-shapes + :page-id page-id + :file-id file-id + :shared-libs shared-libs}])]] + [:& tab-element {:id :prototype + :title (tr "workspace.options.prototype")} + [:div {:class (stl/css :element-options)} + [:& interactions-menu {:shape (first shapes)}]]] + [:& tab-element {:id :inspect + :title (tr "workspace.options.inspect")} + [:div {:class (stl/css :element-options)} + [:& hrs/right-sidebar {:page-id page-id + :objects objects + :file-id file-id + :frame shape-parent-frame + :shapes selected-shapes + :on-change-section on-change-section + :on-expand on-expand + :from :workspace}]]]]])) ;; TODO: this need optimizations, selected-objects and ;; selected-objects-with-children are derefed always but they only diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.scss b/frontend/src/app/main/ui/workspace/sidebar/options.scss index 46aeb77458..7b67bcf8c6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options.scss @@ -13,24 +13,24 @@ width: 100%; height: 100%; padding-left: $s-12; - - .tab-spacing { - margin-right: $s-12; - margin-bottom: $s-8; - } - - .content-class { - overflow-y: auto; - overflow-x: hidden; - height: calc(100vh - $s-96); - scrollbar-gutter: stable; - } - - .element-options { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - gap: $s-8; - } +} + +.tab-spacing { + margin-right: $s-12; + margin-bottom: $s-8; +} + +.content-class { + overflow-y: auto; + overflow-x: hidden; + height: calc(100vh - $s-96); + scrollbar-gutter: stable; +} + +.element-options { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + gap: $s-8; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs index dbe756c224..1efb38e5a0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs @@ -8,27 +8,19 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] - [app.main.ui.context :as ctx] [app.util.dom :as dom] [rumext.v2 :as mf])) (mf/defc advanced-options [{:keys [visible? class children]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - ref (mf/use-ref nil)] + (let [ref (mf/use-ref nil)] (mf/use-effect (mf/deps visible?) (fn [] (when-let [node (mf/ref-val ref)] (when visible? (dom/scroll-into-view-if-needed! node))))) - (if new-css-system - (when visible? - [:div {:class (dm/str class " " (stl/css :advanced-options-wrapper)) - :ref ref} - children]) - - (when visible? - [:div.advanced-options-wrapper {:ref ref} - [:div.advanced-options {} - children]])))) + (when visible? + [:div {:class (dm/str class " " (stl/css :advanced-options-wrapper)) + :ref ref} + children]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs index 1632e7b51a..fc7758d99f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs @@ -11,7 +11,6 @@ [app.main.data.workspace.shortcuts :as sc] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -19,9 +18,8 @@ (mf/defc align-options [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - selected (mf/deref refs/selected-shapes) - ;; don't need to watch objects, only read the value + (let [selected (mf/deref refs/selected-shapes) + ;; don't need to watch objects, only read the value objects (deref refs/workspace-page-objects) disabled-align (not (dw/can-align? selected objects)) @@ -44,130 +42,70 @@ (st/emit! (dw/distribute-objects value)))))] (when (not (and disabled-align disabled-distribute)) - (if new-css-system - [:div {:class (stl/css :align-options)} - [:div {:class (stl/css :align-group)} - [:button {:class (stl/css-case :align-button true - :disabled disabled-align) - :disabled disabled-align - :title (tr "workspace.align.hleft" (sc/get-tooltip :align-left)) - :data-value :hleft - :on-click align-objects} - i/align-left-refactor] + [:div {:class (stl/css :align-options)} + [:div {:class (stl/css :align-group)} + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.hleft" (sc/get-tooltip :align-left)) + :data-value :hleft + :on-click align-objects} + i/align-left-refactor] - [:button {:class (stl/css-case :align-button true - :disabled disabled-align) - :disabled disabled-align - :title (tr "workspace.align.hcenter" (sc/get-tooltip :align-hcenter)) - :data-value :hcenter - :on-click align-objects} - i/align-horizontal-center-refactor] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.hcenter" (sc/get-tooltip :align-hcenter)) + :data-value :hcenter + :on-click align-objects} + i/align-horizontal-center-refactor] - [:button {:class (stl/css-case :align-button true - :disabled disabled-align) - :disabled disabled-align - :title (tr "workspace.align.hright" (sc/get-tooltip :align-right)) - :data-value :hright - :on-click align-objects} - i/align-right-refactor] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.hright" (sc/get-tooltip :align-right)) + :data-value :hright + :on-click align-objects} + i/align-right-refactor] - [:button {:class (stl/css-case :align-button true - :disabled disabled-distribute) - :disabled disabled-distribute - :title (tr "workspace.align.hdistribute" (sc/get-tooltip :h-distribute)) - :data-value :horizontal - :on-click distribute-objects} - i/distribute-horizontally-refactor]] + [:button {:class (stl/css-case :align-button true + :disabled disabled-distribute) + :disabled disabled-distribute + :title (tr "workspace.align.hdistribute" (sc/get-tooltip :h-distribute)) + :data-value :horizontal + :on-click distribute-objects} + i/distribute-horizontally-refactor]] - [:div {:class (stl/css :align-group)} - [:button {:class (stl/css-case :align-button true - :disabled disabled-align) - :disabled disabled-align - :title (tr "workspace.align.vtop" (sc/get-tooltip :align-top)) - :data-value :vtop - :on-click align-objects} - i/align-top-refactor] + [:div {:class (stl/css :align-group)} + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.vtop" (sc/get-tooltip :align-top)) + :data-value :vtop + :on-click align-objects} + i/align-top-refactor] - [:button {:class (stl/css-case :align-button true - :disabled disabled-align) - :disabled disabled-align - :title (tr "workspace.align.vcenter" (sc/get-tooltip :align-vcenter)) - :data-value :vcenter - :on-click align-objects} - i/align-vertical-center-refactor] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.vcenter" (sc/get-tooltip :align-vcenter)) + :data-value :vcenter + :on-click align-objects} + i/align-vertical-center-refactor] - [:button {:class (stl/css-case :align-button true - :disabled disabled-align) - :disabled disabled-align - :title (tr "workspace.align.vbottom" (sc/get-tooltip :align-bottom)) - :data-value :vbottom - :on-click align-objects} - i/align-bottom-refactor] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.vbottom" (sc/get-tooltip :align-bottom)) + :data-value :vbottom + :on-click align-objects} + i/align-bottom-refactor] - [:button {:title (tr "workspace.align.vdistribute" (sc/get-tooltip :v-distribute)) - :class (stl/css-case :align-button true - :disabled disabled-distribute) - :disabled disabled-distribute - :data-value :vertical - :on-click distribute-objects} - i/distribute-vertical-spacing-refactor]]] - - [:div.align-options - [:div.align-group - [:div.align-button.tooltip.tooltip-bottom - {:alt (tr "workspace.align.hleft" (sc/get-tooltip :align-left)) - :class (when disabled-align "disabled") - :data-value :hleft - :on-click align-objects} - i/shape-halign-left] - - [:div.align-button.tooltip.tooltip-bottom - {:alt (tr "workspace.align.hcenter" (sc/get-tooltip :align-hcenter)) - :class (when disabled-align "disabled") - :data-value :hcenter - :on-click align-objects} - i/shape-halign-center] - - [:div.align-button.tooltip.tooltip-bottom - {:alt (tr "workspace.align.hright" (sc/get-tooltip :align-right)) - :class (when disabled-align "disabled") - :data-value :hright - :on-click align-objects} - i/shape-halign-right] - - [:div.align-button.tooltip.tooltip-bottom - {:alt (tr "workspace.align.hdistribute" (sc/get-tooltip :h-distribute)) - :class (when disabled-distribute "disabled") - :data-value :horizontal - :on-click distribute-objects} - i/shape-hdistribute]] - - [:div.align-group - [:div.align-button.tooltip.tooltip-bottom-left - {:alt (tr "workspace.align.vtop" (sc/get-tooltip :align-top)) - :class (when disabled-align "disabled") - :data-value :vtop - :on-click align-objects} - i/shape-valign-top] - - [:div.align-button.tooltip.tooltip-bottom-left - {:alt (tr "workspace.align.vcenter" (sc/get-tooltip :align-vcenter)) - :class (when disabled-align "disabled") - :data-value :vcenter - :on-click align-objects} - i/shape-valign-center] - - [:div.align-button.tooltip.tooltip-bottom-left - {:alt (tr "workspace.align.vbottom" (sc/get-tooltip :align-bottom)) - :class (when disabled-align "disabled") - :data-value :vbottom - :on-click align-objects} - i/shape-valign-bottom] - - [:div.align-button.tooltip.tooltip-bottom-left - {:alt (tr "workspace.align.vdistribute" (sc/get-tooltip :v-distribute)) - :class (when disabled-distribute "disabled") - :data-value :vertical - :on-click distribute-objects} - i/shape-vdistribute]]])))) + [:button {:title (tr "workspace.align.vdistribute" (sc/get-tooltip :v-distribute)) + :class (stl/css-case :align-button true + :disabled disabled-distribute) + :disabled disabled-distribute + :data-value :vertical + :on-click distribute-objects} + i/distribute-vertical-spacing-refactor]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss index d141e7fd59..8294f1d8b7 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss @@ -11,29 +11,30 @@ gap: $s-4; height: $s-32; margin: 0 calc(-1 * $s-2); - .align-group { - @include flexRow; - .align-button { - @extend .button-tertiary; - height: $s-28; - width: $s-28; - padding: 0; - border-radius: $br-8; +} +.align-group { + @include flexRow; +} + +.align-button { + @extend .button-tertiary; + height: $s-28; + width: $s-28; + padding: 0; + border-radius: $br-8; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + &.disabled { + cursor: default; + svg { + stroke: var(--button-background-color-disabled); + } + &:hover { + background-color: var(--panel-background-color); svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - &.disabled { - cursor: default; - svg { - stroke: var(--button-background-color-disabled); - } - &:hover { - background-color: var(--panel-background-color); - svg { - stroke: var(--button-background-color-disabled); - } - } + stroke: var(--button-background-color-disabled); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs index d24bce38a2..989d262b11 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs @@ -12,9 +12,7 @@ [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -28,10 +26,8 @@ :hidden false})) (mf/defc blur-menu [{:keys [ids type values]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - blur (:blur values) + (let [blur (:blur values) has-value? (not (nil? blur)) - multiple? (= blur :multiple) state* (mf/use-state {:show-content true :show-more-options false}) @@ -79,76 +75,47 @@ (fn [] (change! #(update-in % [:blur :hidden] not))))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-value? - :collapsed? (not open?) - :on-collapsed toggle-content - :title (case type - :multiple (tr "workspace.options.blur-options.title.multiple") - :group (tr "workspace.options.blur-options.title.group") - (tr "workspace.options.blur-options.title")) - :class (stl/css-case :title-spacing-blur (not has-value?))} - (when-not has-value? - [:button {:class (stl/css :add-blur) - :on-click handle-add} i/add-refactor])]] - (when (and open? has-value?) - [:div {:class (stl/css :element-set-content)} - [:div {:class (stl/css-case :first-row true - :hidden hidden?)} - [:div {:class (stl/css :blur-info)} - [:button {:class (stl/css-case :show-more true - :selected more-options?) - :on-click toggle-more-options} - i/menu-refactor] - [:span {:class (stl/css :label)} - (tr "workspace.options.blur-options.title")]] - [:div {:class (stl/css :actions)} - [:button {:class (stl/css :action-btn) - :on-click handle-toggle-visibility} - (if hidden? - i/hide-refactor - i/shown-refactor)] - [:button {:class (stl/css :action-btn) - :on-click handle-delete} i/remove-refactor]]] - (when more-options? - [:div {:class (stl/css :second-row)} - [:label {:class (stl/css :label) - :for "blur-input-sidebar"} - (tr "inspect.attributes.blur.value")] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :id "blur-input-sidebar" - :min "0" - :on-change handle-change - :value (:value blur)}]])])] - - - [:div.element-set - [:div.element-set-title - [:span - (case type - :multiple (tr "workspace.options.blur-options.title.multiple") - :group (tr "workspace.options.blur-options.title.group") - (tr "workspace.options.blur-options.title"))] - - [:div.element-set-title-actions - (when (and has-value? (not multiple?)) - [:div.add-page {:on-click handle-toggle-visibility} - (if hidden? i/eye-closed i/eye)]) - - (if has-value? - [:div.add-page {:on-click handle-delete} i/minus] - [:div.add-page {:on-click handle-add} i/close])]] - - (cond - has-value? - [:div.element-set-content - [:& input-row {:label "Value" - :class "pixels" - :min "0" - :value (:value blur) - :placeholder (tr "settings.multiple") - :on-change handle-change}]])]))) + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-value? + :collapsed? (not open?) + :on-collapsed toggle-content + :title (case type + :multiple (tr "workspace.options.blur-options.title.multiple") + :group (tr "workspace.options.blur-options.title.group") + (tr "workspace.options.blur-options.title")) + :class (stl/css-case :title-spacing-blur (not has-value?))} + (when-not has-value? + [:button {:class (stl/css :add-blur) + :on-click handle-add} i/add-refactor])]] + (when (and open? has-value?) + [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css-case :first-row true + :hidden hidden?)} + [:div {:class (stl/css :blur-info)} + [:button {:class (stl/css-case :show-more true + :selected more-options?) + :on-click toggle-more-options} + i/menu-refactor] + [:span {:class (stl/css :label)} + (tr "workspace.options.blur-options.title")]] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click handle-toggle-visibility} + (if hidden? + i/hide-refactor + i/shown-refactor)] + [:button {:class (stl/css :action-btn) + :on-click handle-delete} i/remove-refactor]]] + (when more-options? + [:div {:class (stl/css :second-row)} + [:label {:class (stl/css :label) + :for "blur-input-sidebar"} + (tr "inspect.attributes.blur.value")] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :id "blur-input-sidebar" + :min "0" + :on-change handle-change + :value (:value blur)}]])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss index 6559fdd1d4..87f3b39d84 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss @@ -8,13 +8,74 @@ .element-set { margin: 0; - .element-title { - .title-spacing-blur { - padding-left: $s-2; - margin: 0; +} + +.title-spacing-blur { + padding-left: $s-2; + margin: 0; +} + +.add-blur { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.element-set-content { + @include flexColumn; + margin-bottom: $s-8; +} + +.first-row { + @include flexRow; + width: 100%; + .blur-info { + display: flex; + align-items: center; + gap: $s-1; + flex-grow: 1; + border-radius: $br-8; + background-color: var(--input-details-color); + .show-more { + @extend .button-secondary; + height: $s-32; + width: $s-28; + border-radius: $br-8 0 0 $br-8; + box-sizing: border-box; + border: $s-1 solid var(--button-secondary-background-color-rest); + svg { + @extend .button-icon; + } + &.selected { + background-color: var(--button-radio-background-color-active); + svg { + stroke: var(--button-radio-foreground-color-active); + } + } } - .add-blur { + .label { + @include titleTipography; + flex-grow: 1; + display: flex; + align-items: center; + height: $s-32; + padding: 0 $s-8; + border-radius: 0 $br-8 $br-8 0; + background-color: var(--input-background-color); + color: var(--menu-foreground-color); + box-sizing: border-box; + border: $s-1 solid var(--input-background-color); + } + } + .actions { + @include flexRow; + .action-btn { @extend .button-tertiary; + box-sizing: border-box; + border: $s-1 solid var(--button-tertiary-background-color-rest); height: $s-32; width: $s-28; svg { @@ -22,85 +83,27 @@ } } } - .element-set-content { - @include flexColumn; - margin-bottom: $s-8; - .first-row { - @include flexRow; - width: 100%; - .blur-info { - display: flex; - align-items: center; - gap: $s-1; - flex-grow: 1; - border-radius: $br-8; - background-color: var(--input-details-color); - .show-more { - @extend .button-secondary; - height: $s-32; - width: $s-28; - border-radius: $br-8 0 0 $br-8; - box-sizing: border-box; - border: $s-1 solid var(--button-secondary-background-color-rest); - svg { - @extend .button-icon; - } - &.selected { - background-color: var(--button-radio-background-color-active); - svg { - stroke: var(--button-radio-foreground-color-active); - } - } - } - .label { - @include titleTipography; - flex-grow: 1; - display: flex; - align-items: center; - height: $s-32; - padding: 0 $s-8; - border-radius: 0 $br-8 $br-8 0; - background-color: var(--input-background-color); - color: var(--menu-foreground-color); - box-sizing: border-box; - border: $s-1 solid var(--input-background-color); - } - } - .actions { - @include flexRow; - .action-btn { - @extend .button-tertiary; - box-sizing: border-box; - border: $s-1 solid var(--button-tertiary-background-color-rest); - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - &.hidden { - .blur-info { - @include hiddenElement; - .show-more { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - } - .label { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - } - } + &.hidden { + .blur-info { + @include hiddenElement; + .show-more { + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); } - } - .second-row { - @extend .input-element; - width: $s-92; .label { - padding-left: $s-8; - width: $s-60; + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); } } } } + +.second-row { + @extend .input-element; + width: $s-92; + .label { + padding-left: $s-8; + width: $s-60; + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs index bae6919402..7a25e1bf55 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs @@ -13,19 +13,13 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) - - (mf/defc bool-options [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - selected (mf/deref refs/selected-objects) + (let [selected (mf/deref refs/selected-objects) head (first selected) selected-with-children (mf/deref refs/selected-shapes-with-children) has-invalid-shapes? (->> selected-with-children @@ -42,39 +36,10 @@ disabled-flatten (or (empty? selected) has-invalid-shapes?) set-bool - (mf/use-fn - (mf/deps head head-bool-type selected) - (fn [event] - (let [bool-type (-> (dom/get-current-target event) - (dom/get-data "value") - (keyword))] - (cond - (> (count selected) 1) - (st/emit! (dw/create-bool (if new-css-system - (keyword bool-type) - bool-type))) - - (and (= (count selected) 1) is-group?) - (st/emit! (dw/group-to-bool (:id head) (if new-css-system - (keyword bool-type) - bool-type))) - - (and (= (count selected) 1) is-bool?) - (if (= head-bool-type (if new-css-system - (keyword bool-type) - bool-type)) - (st/emit! (dw/bool-to-group (:id head))) - (st/emit! (dw/change-bool-type (:id head) (if new-css-system - (keyword bool-type) - bool-type)))))))) - - set-bool-refactor (mf/use-fn (mf/deps selected is-group? is-bool?) (fn [bool-type] - (let [bool-type (if new-css-system - (keyword bool-type) - bool-type)] + (let [bool-type (keyword bool-type)] (cond (> (count selected) 1) (st/emit! (dw/create-bool bool-type)) @@ -90,82 +55,40 @@ flatten-objects (mf/use-fn #(st/emit! (dw/convert-selected-to-path)))] (when (not (and disabled-bool-btns disabled-flatten)) - (if new-css-system - [:div {:class (stl/css :boolean-options)} - [:div {:class (stl/css :bool-group)} - [:& radio-buttons {:selected (d/name head-bool-type) - :class (stl/css :boolean-radio-btn) - :on-change set-bool-refactor - :name "bool-options"} - [:& radio-button {:icon i/boolean-union-refactor - :value "union" - :disabled disabled-bool-btns - :title (str (tr "workspace.shape.menu.union") " (" (sc/get-tooltip :bool-union) ")") - :id "bool-opt-union"}] - [:& radio-button {:icon i/boolean-difference-refactor - :value "difference" - :disabled disabled-bool-btns - :title (str (tr "workspace.shape.menu.difference") " (" (sc/get-tooltip :bool-difference) ")") - :id "bool-opt-differente"}] - [:& radio-button {:icon i/boolean-intersection-refactor - :value "intersection" - :disabled disabled-bool-btns - :title (str (tr "intersection") " (" (sc/get-tooltip :bool-intersection) ")") - :id "bool-opt-intersection"}] - [:& radio-button {:icon i/boolean-exclude-refactor - :value "exclude" - :disabled disabled-bool-btns - :title (str (tr "exclude") " (" (sc/get-tooltip :bool-exclude) ")") - :id "bool-opt-exclude"}]]] + [:div {:class (stl/css :boolean-options)} + [:div {:class (stl/css :bool-group)} + [:& radio-buttons {:selected (d/name head-bool-type) + :class (stl/css :boolean-radio-btn) + :on-change set-bool + :name "bool-options"} + [:& radio-button {:icon i/boolean-union-refactor + :value "union" + :disabled disabled-bool-btns + :title (str (tr "workspace.shape.menu.union") " (" (sc/get-tooltip :bool-union) ")") + :id "bool-opt-union"}] + [:& radio-button {:icon i/boolean-difference-refactor + :value "difference" + :disabled disabled-bool-btns + :title (str (tr "workspace.shape.menu.difference") " (" (sc/get-tooltip :bool-difference) ")") + :id "bool-opt-differente"}] + [:& radio-button {:icon i/boolean-intersection-refactor + :value "intersection" + :disabled disabled-bool-btns + :title (str (tr "intersection") " (" (sc/get-tooltip :bool-intersection) ")") + :id "bool-opt-intersection"}] + [:& radio-button {:icon i/boolean-exclude-refactor + :value "exclude" + :disabled disabled-bool-btns + :title (str (tr "exclude") " (" (sc/get-tooltip :bool-exclude) ")") + :id "bool-opt-exclude"}]]] - [:div {:class (stl/css :bool-group)} - [:button - {:title (tr "workspace.shape.menu.flatten") - :class (stl/css-case - :flatten true - :disabled disabled-flatten) - :disabled disabled-flatten - :on-click flatten-objects} - i/boolean-flatten-refactor]]] - - [:div.align-options - [:div.align-group - [:div.align-button.tooltip.tooltip-bottom - {:alt (str (tr "workspace.shape.menu.union") " (" (sc/get-tooltip :bool-union) ")") - :class (dom/classnames :disabled disabled-bool-btns - :selected (= head-bool-type :union)) - :data-value :union - :on-click set-bool} - i/bool-union] - - [:div.align-button.tooltip.tooltip-bottom - {:alt (str (tr "workspace.shape.menu.difference") " (" (sc/get-tooltip :bool-difference) ")") - :class (dom/classnames :disabled disabled-bool-btns - :selected (= head-bool-type :difference)) - :data-value :difference - :on-click set-bool} - i/bool-difference] - - [:div.align-button.tooltip.tooltip-bottom - {:alt (str (tr "workspace.shape.menu.intersection") " (" (sc/get-tooltip :bool-intersection) ")") - :class (dom/classnames :disabled disabled-bool-btns - :selected (= head-bool-type :intersection)) - :data-value :intersection - :on-click set-bool} - i/bool-intersection] - - [:div.align-button.tooltip.tooltip-bottom - {:alt (str (tr "workspace.shape.menu.exclude") " (" (sc/get-tooltip :bool-exclude) ")") - :class (dom/classnames :disabled disabled-bool-btns - :selected (= head-bool-type :exclude)) - :data-value :exclude - :on-click set-bool} - i/bool-exclude]] - - [:div.align-group - [:div.align-button.tooltip.tooltip-bottom - {:alt (tr "workspace.shape.menu.flatten") - :class (dom/classnames :disabled disabled-flatten) - :on-click flatten-objects} - i/bool-flatten]]])))) + [:div {:class (stl/css :bool-group)} + [:button + {:title (tr "workspace.shape.menu.flatten") + :class (stl/css-case + :flatten true + :disabled disabled-flatten) + :disabled disabled-flatten + :on-click flatten-objects} + i/boolean-flatten-refactor]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss index bf08806f5e..3cf1fa8fe6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss @@ -11,33 +11,36 @@ gap: $s-4; height: $s-32; margin: 0 calc(-1 * $s-2); - .bool-group { - display: flex; - align-items: center; - .flatten { - @extend .button-tertiary; - height: $s-28; - width: $s-28; - border-radius: $br-8; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - &.disabled { - cursor: default; - svg { - stroke: var(--button-background-color-disabled); - } - &:hover { - background-color: var(--panel-background-color); - svg { - stroke: var(--button-background-color-disabled); - } - } - } +} + +.bool-group { + display: flex; + align-items: center; +} + +.flatten { + @extend .button-tertiary; + height: $s-28; + width: $s-28; + border-radius: $br-8; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + &.disabled { + cursor: default; + svg { + stroke: var(--button-background-color-disabled); } - .boolean-radio-btn { - background-color: transparent; + &:hover { + background-color: var(--panel-background-color); + svg { + stroke: var(--button-background-color-disabled); + } } } } + +.boolean-radio-btn { + background-color: transparent; +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs index 47aac34fb4..6dce1cc000 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs @@ -14,8 +14,6 @@ [app.main.data.workspace.selection :as dws] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] - [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] @@ -158,7 +156,6 @@ [{:keys [shapes file-id shared-libs] :as props}] (let [{:keys [grouped-colors library-colors colors]} (mf/with-memo [shapes file-id shared-libs] (prepare-colors shapes file-id shared-libs)) - new-css-system (mf/use-ctx ctx/new-css-system) state* (mf/use-state true) open? (deref state*) @@ -216,71 +213,17 @@ (mf/with-effect [grouped-colors] (reset! grouped-colors* grouped-colors)) - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-colors? - :collapsed? (not open?) - :on-collapsed toggle-content - :title (tr "workspace.options.selection-color") - :class (stl/css-case :title-spacing-selected-colors (not has-colors?))}]] + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-colors? + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.options.selection-color") + :class (stl/css-case :title-spacing-selected-colors (not has-colors?))}]] - (when open? - [:div {:class (stl/css :element-content)} - [:div {:class (stl/css :selected-color-group)} - (for [[index color] (d/enumerate (take 3 library-colors))] - [:& color-row {:key (dm/str "library-color-" (:color color)) - :color color - :index index - :on-detach on-detach - :select-only select-only - :on-change #(on-change %1 color %2) - :on-open on-open - :on-close on-close}]) - (when (and (false? @expand-lib-color) (< 3 (count library-colors))) - [:button {:class (stl/css :more-colors-btn) - :on-click #(reset! expand-lib-color true)} - (tr "workspace.options.more-lib-colors")]) - (when @expand-lib-color - (for [[index color] (d/enumerate (drop 3 library-colors))] - [:& color-row {:key (dm/str "library-color-" (:color color)) - :color color - :index index - :on-detach on-detach - :select-only select-only - :on-change #(on-change %1 color %2) - :on-open on-open - :on-close on-close}]))] - [:div {:class (stl/css :selected-color-group)} - (for [[index color] (d/enumerate (take 3 colors))] - [:& color-row {:key (dm/str "color-" index) - :color color - :index index - :select-only select-only - :on-change #(on-change %1 color %2) - :on-open on-open - :on-close on-close}]) - (when (and (false? @expand-color) (< 3 (count colors))) - [:button {:class (stl/css :more-colors-btn) - :on-click #(reset! expand-color true)} - (tr "workspace.options.more-colors")]) - - (when @expand-color - (for [[index color] (d/enumerate (drop 3 colors))] - [:& color-row {:key (dm/str "color-" (:color color)) - :color color - :index index - :select-only select-only - :on-change #(on-change %1 color %2) - :on-open on-open - :on-close on-close}]))]])] - - - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.options.selection-color")]] - [:div.element-set-content - [:div.selected-colors + (when open? + [:div {:class (stl/css :element-content)} + [:div {:class (stl/css :selected-color-group)} (for [[index color] (d/enumerate (take 3 library-colors))] [:& color-row {:key (dm/str "library-color-" (:color color)) :color color @@ -291,9 +234,9 @@ :on-open on-open :on-close on-close}]) (when (and (false? @expand-lib-color) (< 3 (count library-colors))) - [:div.expand-colors {:on-click #(reset! expand-lib-color true)} - [:span i/actions] - [:span.text (tr "workspace.options.more-lib-colors")]]) + [:button {:class (stl/css :more-colors-btn) + :on-click #(reset! expand-lib-color true)} + (tr "workspace.options.more-lib-colors")]) (when @expand-lib-color (for [[index color] (d/enumerate (drop 3 library-colors))] [:& color-row {:key (dm/str "library-color-" (:color color)) @@ -304,8 +247,7 @@ :on-change #(on-change %1 color %2) :on-open on-open :on-close on-close}]))] - - [:div.selected-colors + [:div {:class (stl/css :selected-color-group)} (for [[index color] (d/enumerate (take 3 colors))] [:& color-row {:key (dm/str "color-" index) :color color @@ -315,9 +257,10 @@ :on-open on-open :on-close on-close}]) (when (and (false? @expand-color) (< 3 (count colors))) - [:div.expand-colors {:on-click #(reset! expand-color true)} - [:span i/actions] - [:span.text (tr "workspace.options.more-colors")]]) + [:button {:class (stl/css :more-colors-btn) + :on-click #(reset! expand-color true)} + (tr "workspace.options.more-colors")]) + (when @expand-color (for [[index color] (d/enumerate (drop 3 colors))] [:& color-row {:key (dm/str "color-" (:color color)) @@ -326,4 +269,4 @@ :select-only select-only :on-change #(on-change %1 color %2) :on-open on-open - :on-close on-close}]))]]]))) + :on-close on-close}]))]])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss index eb8ca850c3..56e096768f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss @@ -8,30 +8,33 @@ .element-set { margin: 0; - .element-title { - .title-spacing-selected-colors { - padding-left: $s-2; - margin: 0; - } - .add-fill { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - .element-content { - @include flexColumn; - margin-bottom: $s-8; - .selected-color-group { - @include flexColumn; - .more-colors-btn { - @extend .button-secondary; - @include tabTitleTipography; - height: $s-32; - } - } +} + +.title-spacing-selected-colors { + padding-left: $s-2; + margin: 0; +} + +.add-fill { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; } } + +.element-content { + @include flexColumn; + margin-bottom: $s-8; +} + +.selected-color-group { + @include flexColumn; +} + +.more-colors-btn { + @extend .button-secondary; + @include tabTitleTipography; + height: $s-32; +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index c000ac90c8..40cef86426 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -147,7 +147,6 @@ (when (or @editing? creating?) [:div.counter (str @size "/300")])]]))) - (mf/defc component-swap-item {::mf/wrap-props false} [{:keys [item loop shapes file-id root-shape container component-id is-search listing-thumbs] :as props}] @@ -190,7 +189,6 @@ [:span {:class (stl/css :component-group-name)} (cfh/last-path group-name)]] [:span i/arrow-slide]])) - (mf/defc component-swap [{:keys [shapes] :as props}] (let [single? (= 1 (count shapes)) @@ -405,7 +403,6 @@ [:span {:class (stl/css :dropdown-label)} (tr (:msg entry))]])]])) - (mf/defc component-menu [{:keys [shapes swap-opened?] :as props}] (let [current-file-id (mf/use-ctx ctx/current-file-id) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index a61c6314a3..35b72810ef 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -16,7 +16,6 @@ [app.main.store :as st] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -31,9 +30,7 @@ (mf/defc constraints-menu [{:keys [ids values] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - state* (mf/use-state true) + (let [state* (mf/use-state true) open? (deref state*) toggle-content (mf/use-fn #(swap! state* not)) @@ -109,19 +106,6 @@ ids #(assoc % constraint new-value)))))) - on-constraint-select-changed - (mf/use-fn - (mf/deps ids) - (fn [event] - (let [constraint (-> (dom/get-current-target event) - (dom/get-data "value") - (keyword)) - value (-> (dom/get-target-val event) (keyword))] - (when-not (str/empty? value) - (st/emit! (dch/update-shapes - ids - #(assoc % constraint value))))))) - on-constraint-h-select-changed (mf/use-fn (mf/deps ids) @@ -171,154 +155,79 @@ ;; CONSTRAINTS (when in-frame? - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? true - :collapsed? (not open?) - :on-collapsed toggle-content - :title (tr "workspace.options.constraints")}]] - (when open? - [:div {:class (stl/css :element-set-content)} - [:div {:class (stl/css :constraints-widget)} - [:div {:class (stl/css :constraints-top)} - [:button {:class (stl/css-case :constraint-btn true - :active (or (= constraints-v :top) - (= constraints-v :topbottom))) - :data-value :top - :on-click on-constraint-button-clicked} - [:span {:class (stl/css :resalted-area)}]]] - [:div {:class (stl/css :constraints-left)} - [:button {:class (stl/css-case :constraint-btn true - :constraint-btn-rotated true - :active (or (= constraints-h :left) - (= constraints-h :leftright))) - :data-value :left - :on-click on-constraint-button-clicked} - [:span {:class (stl/css :resalted-area)}]]] - [:div {:class (stl/css :constraints-center)} - [:button {:class (stl/css-case :constraint-btn true - :active (= constraints-h :center)) - :data-value :centerh - :on-click on-constraint-button-clicked} - [:span {:class (stl/css :resalted-area)}]] - [:button {:class (stl/css-case :constraint-btn-special true - :constraint-btn-rotated true - :active (= constraints-v :center)) - :data-value :centerv - :on-click on-constraint-button-clicked} - [:span {:class (stl/css :resalted-area)}]]] - [:div {:class (stl/css :constraints-right)} - [:button {:class (stl/css-case :constraint-btn true - :constraint-btn-rotated true - :active (or (= constraints-h :right) - (= constraints-h :leftright))) - :data-value :right - :on-click on-constraint-button-clicked} - [:span {:class (stl/css :resalted-area)}]]] - [:div {:class (stl/css :constraints-bottom)} - [:button {:class (stl/css-case :constraint-btn true - :active (or (= constraints-v :bottom) - (= constraints-v :topbottom))) - :data-value :bottom - :on-click on-constraint-button-clicked} - [:span {:class (stl/css :resalted-area)}]]]] - [:div {:class (stl/css :contraints-selects)} - [:div {:class (stl/css :horizontal-select)} - [:& select - {:default-value (d/name constraints-h "scale") - :options options-h - :on-change on-constraint-h-select-changed}]] - [:div {:class (stl/css :vertical-select)} - [:& select - {:default-value (d/name constraints-v "scale") - :options options-v - :on-change on-constraint-v-select-changed}]] - (when first-level? - [:div {:class (stl/css :checkbox)} + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.options.constraints")}]] + (when open? + [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :constraints-widget)} + [:div {:class (stl/css :constraints-top)} + [:button {:class (stl/css-case :constraint-btn true + :active (or (= constraints-v :top) + (= constraints-v :topbottom))) + :data-value :top + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-left)} + [:button {:class (stl/css-case :constraint-btn true + :constraint-btn-rotated true + :active (or (= constraints-h :left) + (= constraints-h :leftright))) + :data-value :left + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-center)} + [:button {:class (stl/css-case :constraint-btn true + :active (= constraints-h :center)) + :data-value :centerh + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]] + [:button {:class (stl/css-case :constraint-btn-special true + :constraint-btn-rotated true + :active (= constraints-v :center)) + :data-value :centerv + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-right)} + [:button {:class (stl/css-case :constraint-btn true + :constraint-btn-rotated true + :active (or (= constraints-h :right) + (= constraints-h :leftright))) + :data-value :right + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-bottom)} + [:button {:class (stl/css-case :constraint-btn true + :active (or (= constraints-v :bottom) + (= constraints-v :topbottom))) + :data-value :bottom + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]]] + [:div {:class (stl/css :contraints-selects)} + [:div {:class (stl/css :horizontal-select)} + [:& select + {:default-value (d/name constraints-h "scale") + :options options-h + :on-change on-constraint-h-select-changed}]] + [:div {:class (stl/css :vertical-select)} + [:& select + {:default-value (d/name constraints-v "scale") + :options options-v + :on-change on-constraint-v-select-changed}]] + (when first-level? + [:div {:class (stl/css :checkbox)} - [:label {:for "fixed-on-scroll" - :class (stl/css-case :checked (:fixed-scroll values))} - [:span {:class (stl/css-case :check-mark true - :checked (:fixed-scroll values))} - (when (:fixed-scroll values) - i/status-tick-refactor)] - (tr "workspace.options.constraints.fix-when-scrolling") - [:input {:type "checkbox" - :id "fixed-on-scroll" - :checked (:fixed-scroll values) - :on-change on-fixed-scroll-clicked}]]])]])] - - - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.options.constraints")]] - - [:div.element-set-content - [:div.row-flex.align-top - [:div.constraints-widget - [:div.constraints-box] - [:div.constraint-button.top - {:class (dom/classnames :active (or (= constraints-v :top) - (= constraints-v :topbottom))) - :data-value :top - :on-click on-constraint-button-clicked}] - [:div.constraint-button.bottom - {:class (dom/classnames :active (or (= constraints-v :bottom) - (= constraints-v :topbottom))) - :data-value :bottom - :on-click on-constraint-button-clicked}] - [:div.constraint-button.left - {:class (dom/classnames :active (or (= constraints-h :left) - (= constraints-h :leftright))) - :data-value :left - :on-click on-constraint-button-clicked}] - [:div.constraint-button.right - {:class (dom/classnames :active (or (= constraints-h :right) - (= constraints-h :leftright))) - :data-value :right - :on-click on-constraint-button-clicked}] - [:div.constraint-button.centerv - {:class (dom/classnames :active (= constraints-v :center)) - :data-value :centerv - :on-click on-constraint-button-clicked}] - [:div.constraint-button.centerh - {:class (dom/classnames :active (= constraints-h :center)) - :data-value :centerh - :on-click on-constraint-button-clicked}]] - - [:div.constraints-form - [:div.row-flex - [:span.left-right i/full-screen] - [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :data-value :constraints-h - :on-change on-constraint-select-changed - :value (d/name constraints-h "scale")} - (when (= constraints-h :multiple) - [:option {:value ""} (tr "settings.multiple")]) - [:option {:value "left"} (tr "workspace.options.constraints.left")] - [:option {:value "right"} (tr "workspace.options.constraints.right")] - [:option {:value "leftright"} (tr "workspace.options.constraints.leftright")] - [:option {:value "center"} (tr "workspace.options.constraints.center")] - [:option {:value "scale"} (tr "workspace.options.constraints.scale")]]] - [:div.row-flex - [:span.top-bottom i/full-screen] - [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :data-value :constraints-v - :on-change on-constraint-select-changed - :value (d/name constraints-v "scale")} - (when (= constraints-v :multiple) - [:option {:value ""} (tr "settings.multiple")]) - [:option {:value "top"} (tr "workspace.options.constraints.top")] - [:option {:value "bottom"} (tr "workspace.options.constraints.bottom")] - [:option {:value "topbottom"} (tr "workspace.options.constraints.topbottom")] - [:option {:value "center"} (tr "workspace.options.constraints.center")] - [:option {:value "scale"} (tr "workspace.options.constraints.scale")]]] - (when first-level? - [:div.row-flex - [:div.fix-when {:class (dom/classnames :active (:fixed-scroll values)) - :on-click on-fixed-scroll-clicked} - (if (:fixed-scroll values) - i/pin-fill - i/pin) - [:span (tr "workspace.options.constraints.fix-when-scrolling")]]])]]]])))) + [:label {:for "fixed-on-scroll" + :class (stl/css-case :checked (:fixed-scroll values))} + [:span {:class (stl/css-case :check-mark true + :checked (:fixed-scroll values))} + (when (:fixed-scroll values) + i/status-tick-refactor)] + (tr "workspace.options.constraints.fix-when-scrolling") + [:input {:type "checkbox" + :id "fixed-on-scroll" + :checked (:fixed-scroll values) + :on-change on-fixed-scroll-clicked}]]])]])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss index 736bde4e40..cf275fba93 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss @@ -8,149 +8,156 @@ .element-set { margin: 0; - .element-set-content { - display: flex; - gap: $s-4; - .constraints-widget { - background-color: var(--constraint-widget-background-color); - display: grid; - grid-template-columns: $s-24 $s-60 $s-24; - grid-template-rows: $s-24 $s-60 $s-24; - grid-template-areas: - "top top top" - "left center right" - "bottom bottom bottom"; - height: $s-108; - width: $s-108; +} + +.element-set-content { + display: flex; + gap: $s-4; +} + +.constraints-widget { + background-color: var(--constraint-widget-background-color); + display: grid; + grid-template-columns: $s-24 $s-60 $s-24; + grid-template-rows: $s-24 $s-60 $s-24; + grid-template-areas: + "top top top" + "left center right" + "bottom bottom bottom"; + height: $s-108; + width: $s-108; + border-radius: $br-8; +} + +.constraints-top, +.constraints-left, +.constraints-center, +.constraints-right, +.constraints-bottom { + @include flexCenter; + grid-area: top; + .constraint-btn, + .constraint-btn-special, + .constraint-btn-rotated { + @include buttonStyle; + @include flexCenter; + width: 100%; + height: 100%; + .resalted-area { + width: $s-32; + height: $s-3; border-radius: $br-8; - .constraints-top, - .constraints-left, - .constraints-center, - .constraints-right, - .constraints-bottom { - @include flexCenter; - grid-area: top; - .constraint-btn, - .constraint-btn-special, - .constraint-btn-rotated { - @include buttonStyle; - @include flexCenter; - width: 100%; - height: 100%; - .resalted-area { - width: $s-32; - height: $s-3; - border-radius: $br-8; - background-color: var(--button-constraint-background-color-rest); - padding: 0; - margin: 0; - } - &.active .resalted-area { - outline: $s-4 solid var(--button-constraint-border-color-hover); - background-color: var(--button-constraint-background-color-hover); - } - &:hover .resalted-area, - &:focus .resalted-area { - outline: $s-4 solid var(--button-constraint-border-color-hover); - background-color: var(--button-constraint-background-color-hover); - } - } - } - .constraints-left { - grid-area: left; - .constraint-btn-rotated { - height: $s-60; - width: $s-24; - .resalted-area { - height: $s-32; - width: $s-3; - } - } - } - .constraints-center { - grid-area: center; - position: relative; - background-color: var(--constraint-center-area-background-color); - border-radius: $br-8; - .constraint-btn { - width: $s-60; - height: $s-24; - .resalted-area { - width: $s-32; - height: $s-3; - } - } - .constraint-btn-special { - position: absolute; - height: $s-60; - width: $s-24; - .resalted-area { - height: $s-32; - width: $s-3; - } - } - } - .constraints-right { - grid-area: right; - .constraint-btn-rotated { - height: $s-72; - width: $s-24; - .resalted-area { - height: $s-32; - width: $s-3; - } - } - } - .constraints-bottom { - grid-area: bottom; - } + background-color: var(--button-constraint-background-color-rest); + padding: 0; + margin: 0; } - .contraints-selects { - @include flexColumn; + &.active .resalted-area { + outline: $s-4 solid var(--button-constraint-border-color-hover); + background-color: var(--button-constraint-background-color-hover); + } + &:hover .resalted-area, + &:focus .resalted-area { + outline: $s-4 solid var(--button-constraint-border-color-hover); + background-color: var(--button-constraint-background-color-hover); + } + } +} +.constraints-left { + grid-area: left; + .constraint-btn-rotated { + height: $s-60; + width: $s-24; + .resalted-area { + height: $s-32; + width: $s-3; + } + } +} +.constraints-center { + grid-area: center; + position: relative; + background-color: var(--constraint-center-area-background-color); + border-radius: $br-8; + .constraint-btn { + width: $s-60; + height: $s-24; + .resalted-area { + width: $s-32; + height: $s-3; + } + } + .constraint-btn-special { + position: absolute; + height: $s-60; + width: $s-24; + .resalted-area { + height: $s-32; + width: $s-3; + } + } +} - .horizontal-select, - .vertical-select { - width: $s-124; - padding: 0; +.constraints-right { + grid-area: right; + .constraint-btn-rotated { + height: $s-72; + width: $s-24; + .resalted-area { + height: $s-32; + width: $s-3; + } + } +} + +.constraints-bottom { + grid-area: bottom; +} + +.contraints-selects { + @include flexColumn; +} + +.horizontal-select, +.vertical-select { + width: $s-124; + padding: 0; +} + +.checkbox { + display: flex; + align-items: center; + margin-bottom: $s-8; + margin-top: $s-8; + padding-left: 0; + input { + margin: 0; + } + + label { + @include titleTipography; + display: flex; + align-items: center; + gap: $s-2; + cursor: pointer; + color: var(--input-checkbox-text-foreground-color); + .check-mark { + @include flexCenter; + width: $s-16; + height: $s-16; + border-radius: $br-6; + background-color: var(--input-checkbox-inactive-background-color); + &.checked { + background-color: var(--input-checkbox-active-background-color); + svg { + @extend .button-icon-small; + stroke: var(--input-details-color); + } } - - .checkbox { - display: flex; - align-items: center; - margin-bottom: $s-8; - margin-top: $s-8; - padding-left: 0; - input { - margin: 0; - } - label { - @include titleTipography; - display: flex; - align-items: center; - gap: $s-2; - cursor: pointer; - color: var(--input-checkbox-text-foreground-color); - .check-mark { - @include flexCenter; - width: $s-16; - height: $s-16; - border-radius: $br-6; - background-color: var(--input-checkbox-inactive-background-color); - &.checked { - background-color: var(--input-checkbox-active-background-color); - svg { - @extend .button-icon-small; - stroke: var(--input-details-color); - } - } - &:hover { - border-color: var(--input-checkbox-border-color-hover); - } - &:focus { - border-color: var(--input-checkbox-border-color-focus); - } - } - } + &:hover { + border-color: var(--input-checkbox-border-color-hover); + } + &:focus { + border-color: var(--input-checkbox-border-color-focus); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs index f45dffb83e..72556669d0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs @@ -15,7 +15,6 @@ [app.main.store :as st] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.export] [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -30,8 +29,7 @@ (mf/defc exports-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "page-id" "file-id"]))]} [{:keys [ids type values page-id file-id] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - exports (:exports values []) + (let [exports (:exports values []) has-exports? (or (= :multiple exports) (some? (seq exports))) comp-state* (mf/use-state true) @@ -118,11 +116,7 @@ (mf/use-fn (mf/deps ids) (fn [index event] - (let [scale (if new-css-system - (d/parse-double event) - (-> event - (dom/get-target-val) - (d/parse-double)))] + (let [scale (d/parse-double event)] (st/emit! (dch/update-shapes ids (fn [shape] (assoc-in shape [:exports index :scale] scale))))))) @@ -143,11 +137,7 @@ (mf/use-fn (mf/deps ids) (fn [index event] - (let [type (if new-css-system - (keyword event) - (-> event - (dom/get-target-val) - (keyword)))] + (let [type (keyword event)] (st/emit! (dch/update-shapes ids (fn [shape] (assoc-in shape [:exports index :type] type))))))) @@ -179,125 +169,68 @@ {:value "svg" :label "SVG"} {:value "pdf" :label "PDF"}]] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-exports? - :collapsed? (not open?) - :on-collapsed toggle-content - :title (tr (if (> (count ids) 1) "workspace.options.export-multiple" "workspace.options.export")) - :class (stl/css-case :title-spacing-export (not has-exports?))} - [:button {:class (stl/css :add-export) - :on-click add-export} i/add-refactor]]] - (when open? - [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-exports? + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr (if (> (count ids) 1) "workspace.options.export-multiple" "workspace.options.export")) + :class (stl/css-case :title-spacing-export (not has-exports?))} + [:button {:class (stl/css :add-export) + :on-click add-export} i/add-refactor]]] + (when open? + [:div {:class (stl/css :element-set-content)} - (cond - (= :multiple exports) - [:div {:class (stl/css :multiple-exports)} - [:div {:class (stl/css :label)} (tr "settings.multiple")] - [:div {:class (stl/css :actions)} - [:button {:class (stl/css :action-btn) - :on-click on-remove-all} - i/remove-refactor]]] + (cond + (= :multiple exports) + [:div {:class (stl/css :multiple-exports)} + [:div {:class (stl/css :label)} (tr "settings.multiple")] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click on-remove-all} + i/remove-refactor]]] - (seq exports) - [:* - (for [[index export] (d/enumerate exports)] - [:div {:class (stl/css :element-group) - :key index} - [:div {:class (stl/css :input-wrapper)} - [:div {:class (stl/css :format-select)} + (seq exports) + [:* + (for [[index export] (d/enumerate exports)] + [:div {:class (stl/css :element-group) + :key index} + [:div {:class (stl/css :input-wrapper)} + [:div {:class (stl/css :format-select)} + [:& select + {:default-value (d/name (:type export)) + :options format-options + :dropdown-class (stl/css :dropdown-upwards) + :on-change (partial on-type-change index)}]] + (when (scale-enabled? export) + [:div {:class (stl/css :size-select)} [:& select - {:default-value (d/name (:type export)) - :options format-options + {:default-value (str (:scale export)) + :options size-options :dropdown-class (stl/css :dropdown-upwards) - :on-change (partial on-type-change index)}]] - (when (scale-enabled? export) - [:div {:class (stl/css :size-select)} - [:& select - {:default-value (str (:scale export)) - :options size-options - :dropdown-class (stl/css :dropdown-upwards) - :on-change (partial on-scale-change index)}]]) - [:label {:class (stl/css :suffix-input) - :for "suffix-export-input"} - [:input {:class (stl/css :type-input) - :id "suffix-export-input" - :type "text" - :value (:suffix export) - :placeholder (tr "workspace.options.export.suffix") - :data-value index - :on-change on-suffix-change - :on-key-down manage-key-down}]]] + :on-change (partial on-scale-change index)}]]) + [:label {:class (stl/css :suffix-input) + :for "suffix-export-input"} + [:input {:class (stl/css :type-input) + :id "suffix-export-input" + :type "text" + :value (:suffix export) + :placeholder (tr "workspace.options.export.suffix") + :data-value index + :on-change on-suffix-change + :on-key-down manage-key-down}]]] - [:button {:class (stl/css :action-btn) - :on-click (partial delete-export index)} - i/remove-refactor]])]) + [:button {:class (stl/css :action-btn) + :on-click (partial delete-export index)} + i/remove-refactor]])]) - (when (or (= :multiple exports) (seq exports)) - [:button - {:on-click (when-not in-progress? on-download) - :class (stl/css-case - :export-btn true - :btn-disabled in-progress?) - :disabled in-progress?} - (if in-progress? - (tr "workspace.options.exporting-object") - (tr "workspace.options.export-object" (c (count shapes-with-exports))))])])] - - - [:div.element-set.exports-options - [:div.element-set-title - [:span (tr (if (> (count ids) 1) "workspace.options.export-multiple" "workspace.options.export"))] - (when (not (= :multiple exports)) - [:div.add-page {:on-click add-export} i/close])] - - (cond - (= :multiple exports) - [:div.element-set-options-group - [:div.element-set-label (tr "settings.multiple")] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click on-remove-all} - i/minus]]] - - (seq exports) - [:div.element-set-content - (for [[index export] (d/enumerate exports)] - [:div.element-set-options-group - {:key index} - (when (scale-enabled? export) - [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :on-change (partial on-scale-change index) - :value (:scale export)} - [:option {:value "0.5"} "0.5x"] - [:option {:value "0.75"} "0.75x"] - [:option {:value "1"} "1x"] - [:option {:value "1.5"} "1.5x"] - [:option {:value "2"} "2x"] - [:option {:value "4"} "4x"] - [:option {:value "6"} "6x"]]) - [:input.input-text {:value (:suffix export) - :placeholder (tr "workspace.options.export.suffix") - :data-value index - :on-change on-suffix-change - :on-key-down manage-key-down}] - [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (d/name (:type export)) - :on-change (partial on-type-change index)} - [:option {:value "png"} "PNG"] - [:option {:value "jpeg"} "JPEG"] - [:option {:value "svg"} "SVG"] - [:option {:value "pdf"} "PDF"]] - [:div.delete-icon {:on-click (partial delete-export index)} - i/minus]])]) - - (when (or (= :multiple exports) (seq exports)) - [:div.btn-icon-dark.download-button - {:on-click (when-not in-progress? on-download) - :class (dom/classnames - :btn-disabled in-progress?) - :disabled in-progress?} - (if in-progress? - (tr "workspace.options.exporting-object") - (tr "workspace.options.export-object" (c (count shapes-with-exports))))])]))) + (when (or (= :multiple exports) (seq exports)) + [:button + {:on-click (when-not in-progress? on-download) + :class (stl/css-case + :export-btn true + :btn-disabled in-progress?) + :disabled in-progress?} + (if in-progress? + (tr "workspace.options.exporting-object") + (tr "workspace.options.export-object" (c (count shapes-with-exports))))])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss index 414d9f7cbc..42ecf713b6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss @@ -8,12 +8,35 @@ .element-set { margin: 0; - .element-title { - .title-spacing-export { - padding-left: $s-2; - margin: 0; - } - .add-export { +} + +.title-spacing-export { + padding-left: $s-2; + margin: 0; +} + +.add-export { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.element-set-content { + @include flexColumn; + margin: $s-4 0 $s-8 0; +} + +.multiple-exports { + @include flexRow; + .label { + @extend .mixed-bar; + } + .actions { + @include flexRow; + .action-btn { @extend .button-tertiary; height: $s-32; width: $s-28; @@ -22,68 +45,49 @@ } } } - .element-set-content { - @include flexColumn; - margin: $s-4 0 $s-8 0; - .multiple-exports { - @include flexRow; - .label { - @extend .mixed-bar; - } - .actions { - @include flexRow; - .action-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } +} + +.element-group { + @include flexRow; + .input-wrapper { + @include flexRow; + .format-select { + width: $s-60; + padding: 0; + .dropdown-upwards { + bottom: $s-36; + width: $s-80; + top: unset; } } - .element-group { - @include flexRow; - .input-wrapper { - @include flexRow; - .format-select { - width: $s-60; - padding: 0; - .dropdown-upwards { - bottom: $s-36; - width: $s-80; - top: unset; - } - } - .size-select { - width: $s-60; - padding: 0; - .dropdown-upwards { - bottom: $s-36; - top: unset; - width: $s-80; - } - } - .suffix-input { - @extend .input-element; - min-width: $s-92; - flex-grow: 1; - } - } - .action-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } + .size-select { + width: $s-60; + padding: 0; + .dropdown-upwards { + bottom: $s-36; + top: unset; + width: $s-80; } } - .export-btn { - @extend .button-secondary; - @include tabTitleTipography; - height: $s-32; - width: $s-252; + .suffix-input { + @extend .input-element; + min-width: $s-92; + flex-grow: 1; + } + } + .action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; } } } + +.export-btn { + @extend .button-secondary; + @include tabTitleTipography; + height: $s-32; + width: $s-252; +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index 948c5228f4..58fe4f1e92 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -13,7 +13,6 @@ [app.main.data.workspace.colors :as dc] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] @@ -44,8 +43,7 @@ (mf/defc fill-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]} [{:keys [ids type values disable-remove?] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - label (case type + (let [label (case type :multiple (tr "workspace.options.selection-fill") :group (tr "workspace.options.group-fill") (tr "workspace.options.fill")) @@ -137,83 +135,28 @@ (dom/set-attribute! checkbox "indeterminate" true) (dom/remove-attribute! checkbox "indeterminate"))))) - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-fills? - :collapsed? (not open?) - :on-collapsed toggle-content - :title label - :class (stl/css-case :title-spacing-fill (not has-fills?))} + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-fills? + :collapsed? (not open?) + :on-collapsed toggle-content + :title label + :class (stl/css-case :title-spacing-fill (not has-fills?))} - (when (and (not disable-remove?) (not (= :multiple fills))) - [:button {:class (stl/css :add-fill) - :on-click on-add} i/add-refactor])]] - - (when open? - [:div {:class (stl/css :element-content)} - (cond - (= :multiple fills) - [:div {:class (stl/css :element-set-options-group)} - [:div {:class (stl/css :group-label)} - (tr "settings.multiple")] - [:button {:on-click on-remove-all - :class (stl/css :remove-btn)} - i/remove-refactor]] - - (seq fills) - [:& h/sortable-container {} - (for [[index value] (d/enumerate (:fills values []))] - [:& color-row {:color {:color (:fill-color value) - :opacity (:fill-opacity value) - :id (:fill-color-ref-id value) - :file-id (:fill-color-ref-file value) - :gradient (:fill-color-gradient value) - :image (:fill-image value)} - :key index - :index index - :title (tr "workspace.options.fill") - :on-change (on-change index) - :on-reorder (on-reorder index) - :on-detach (on-detach index) - :on-remove (on-remove index) - :disable-drag disable-drag - :on-focus on-focus - :select-on-focus (not @disable-drag) - :on-blur on-blur}])]) - - (when (or (= type :frame) - (and (= type :multiple) (some? (:hide-fill-on-export values)))) - [:div {:class (stl/css :checkbox)} - [:label {:for "show-fill-on-export" - :class (stl/css-case :global/checked (not hide-fill-on-export?))} - [:span {:class (stl/css-case :check-mark true - :checked (not hide-fill-on-export?))} - (when (not hide-fill-on-export?) - i/status-tick-refactor)] - (tr "workspace.options.show-fill-on-export") - [:input {:type "checkbox" - :id "show-fill-on-export" - :ref checkbox-ref - :checked (not hide-fill-on-export?) - :on-change on-change-show-fill-on-export}]]])])] - - ;; OLD - [:div.element-set - [:div.element-set-title - [:span label] - (when (and (not disable-remove?) (not (= :multiple fills))) - [:div.add-page {:on-click on-add} i/close])] - - [:div.element-set-content + (when (and (not disable-remove?) (not (= :multiple fills))) + [:button {:class (stl/css :add-fill) + :on-click on-add} i/add-refactor])]] + (when open? + [:div {:class (stl/css :element-content)} (cond (= :multiple fills) - [:div.element-set-options-group - [:div.element-set-label (tr "settings.multiple")] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click on-remove-all} - i/minus]]] + [:div {:class (stl/css :element-set-options-group)} + [:div {:class (stl/css :group-label)} + (tr "settings.multiple")] + [:button {:on-click on-remove-all + :class (stl/css :remove-btn)} + i/remove-refactor]] (seq fills) [:& h/sortable-container {} @@ -238,12 +181,16 @@ (when (or (= type :frame) (and (= type :multiple) (some? (:hide-fill-on-export values)))) - [:div.input-checkbox - [:input {:type "checkbox" - :id "show-fill-on-export" - :ref checkbox-ref - :checked (not hide-fill-on-export?) - :on-change on-change-show-fill-on-export}] - - [:label {:for "show-fill-on-export"} - (tr "workspace.options.show-fill-on-export")]])]]))) + [:div {:class (stl/css :checkbox)} + [:label {:for "show-fill-on-export" + :class (stl/css-case :global/checked (not hide-fill-on-export?))} + [:span {:class (stl/css-case :check-mark true + :checked (not hide-fill-on-export?))} + (when (not hide-fill-on-export?) + i/status-tick-refactor)] + (tr "workspace.options.show-fill-on-export") + [:input {:type "checkbox" + :id "show-fill-on-export" + :ref checkbox-ref + :checked (not hide-fill-on-export?) + :on-change on-change-show-fill-on-export}]]])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss index 7bcc45db94..08b5581dbd 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss @@ -8,50 +8,58 @@ .element-set { margin: 0; - .element-title { - margin: 0; - .title-spacing-fill { - padding-left: $s-2; - margin: 0; - } - .add-fill { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } +} + +.element-title { + margin: 0; +} + +.title-spacing-fill { + padding-left: $s-2; + margin: 0; +} + +.add-fill { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; } - .element-content { - display: flex; - flex-direction: column; - gap: $s-12; - margin: $s-4 0 $s-8 0; - .element-set-options-group { - @include flexRow; - .group-label { - @extend .mixed-bar; - } - .remove-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - .checkbox { - @extend .input-checkbox; - padding-left: $s-8; - span.checked { - background-color: var(--input-border-color-active); - svg { - @extend .button-icon-small; - stroke: var(--input-details-color); - } - } +} + +.element-content { + display: flex; + flex-direction: column; + gap: $s-12; + margin: $s-4 0 $s-8 0; +} + +.element-set-options-group { + @include flexRow; +} + +.group-label { + @extend .mixed-bar; +} + +.remove-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.checkbox { + @extend .input-checkbox; + padding-left: $s-8; + span.checked { + background-color: var(--input-border-color-active); + svg { + @extend .button-icon-small; + stroke: var(--input-details-color); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs index 2f326dddfb..8191cf0908 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs @@ -15,11 +15,9 @@ [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] - [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row input-row-v2]] [app.util.i18n :as i18n :refer [tr]] [okulary.core :as l] [rumext.v2 :as mf])) @@ -35,8 +33,7 @@ (mf/defc grid-options {::mf/wrap [mf/memo]} [{:keys [shape-id index grid frame-width frame-height default-grid-params]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-change (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/set-frame-grid shape-id index %))) + (let [on-change (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/set-frame-grid shape-id index %))) on-remove (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/remove-frame-grid shape-id index))) on-save-default (mf/use-fn #(st/emit! (dw/set-default-grid (:type %) (:params %)))) @@ -136,215 +133,87 @@ is-default (= (->> grid :params) (->> grid :type default-grid-params))] - (if new-css-system - [:div {:class (stl/css :grid-option)} - [:div {:class (stl/css :grid-title)} - [:div {:class (stl/css-case :option-row true - :hidden is-hidden?)} - [:button {:class (stl/css-case :show-options true - :selected open?) - :on-click toggle-advanced-options} - i/menu-refactor] - [:div {:class (stl/css :type-select-wrapper)} - [:& select - {:class (stl/css :grid-type-select) - :default-value type - :options [{:value :square :label (tr "workspace.options.grid.square")} - {:value :column :label (tr "workspace.options.grid.column")} - {:value :row :label (tr "workspace.options.grid.row")}] - :on-change handle-change-type}]] - (if (= type :square) - [:div {:class (stl/css :grid-size) - :title (tr "workspace.options.size")} - [:> numeric-input* {:min 0.01 - :value (or (:size params) "") - :no-validate true - :className (stl/css :numeric-input) - :on-change (handle-change :params :size)}]] - - [:div {:class (stl/css :editable-select-wrapper)} - [:& editable-select {:value (:size params) - :type "number" - :class (stl/css :column-select) - :input-class (stl/css :numeric-input) - :min 1 - :options size-options - :placeholder "Auto" - :on-change handle-change-size}]])] - - [:div {:class (stl/css :actions)} - [:button {:class (stl/css :action-btn) - :on-click handle-toggle-visibility} - (if display i/shown-refactor i/hide-refactor)] - [:button {:class (stl/css :action-btn) - :on-click on-remove} - i/remove-refactor]]] - - (when (:display grid) - [:& advanced-options {:class (stl/css :grid-advanced-options) - :visible? open? - :on-close toggle-advanced-options} - ;; square - (when (= :square type) - [:div {:class (stl/css :square-row)} - [:div {:class (stl/css :advanced-row)} - [:& color-row {:color (:color params) - :title (tr "workspace.options.grid.params.color") - :disable-gradient true - :disable-image true - :on-change handle-change-color - :on-detach handle-detach-color}] - [:button {:class (stl/css-case :show-more-options true - :selected show-more-options?) - :on-click toggle-more-options} - i/menu-refactor]] - (when show-more-options? - [:div {:class (stl/css :second-row)} - [:button {:class (stl/css-case :btn-options true - :disabled is-default) - :disabled is-default - :on-click handle-use-default} - [:span (tr "workspace.options.grid.params.use-default")]] - [:button {:class (stl/css-case :btn-options true - :disabled is-default) - :disabled is-default - :on-click handle-set-as-default} - [:span (tr "workspace.options.grid.params.set-default")]]])]) - - (when (or (= :column type) (= :row type)) - [:div {:class (stl/css :column-row)} - [:div {:class (stl/css :advanced-row)} - [:div {:class (stl/css :orientation-select-wrapper)} - [:& select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :default-value (:type params) - :class (stl/css :orientation-select) - :options [{:value :stretch :label (tr "workspace.options.grid.params.type.stretch")} - {:value :left :label (if (= type :row) - (tr "workspace.options.grid.params.type.top") - (tr "workspace.options.grid.params.type.left"))} - {:value :center :label (tr "workspace.options.grid.params.type.center")} - {:value :right :label (if (= type :row) - (tr "workspace.options.grid.params.type.bottom") - (tr "workspace.options.grid.params.type.right"))}] - :on-change (handle-change :params :type)}]] - - [:div {:class (stl/css :color-wrapper)} - [:& color-row {:color (:color params) - :title (tr "workspace.options.grid.params.color") - :disable-gradient true - :disable-image true - :on-change handle-change-color - :on-detach handle-detach-color}]]] - - [:div {:class (stl/css :advanced-row)} - [:div {:class (stl/css :height) - :title (if (= :row type) - (tr "workspace.options.grid.params.height") - (tr "workspace.options.grid.params.width"))} - [:span {:class (stl/css :icon-text)} - (if (= :row type) - "H" - "W")] - [:> numeric-input* {:placeholder "Auto" - :on-change handle-change-item-length - :nillable true - :className (stl/css :numeric-input) - :value (or (:item-length params) "")}]] - - [:div {:class (stl/css :gutter) - :title (tr "workspace.options.grid.params.gutter")} - [:span {:class (stl/css-case :icon true - :rotated (= type :row))} i/gap-horizontal-refactor] - [:> numeric-input* {:placeholder "0" - :on-change (handle-change :params :gutter) - :nillable true - :className (stl/css :numeric-input) - :value (or (:gutter params) 0)}]] - - [:div {:class (stl/css :margin) - :title (tr "workspace.options.grid.params.margin")} - [:span {:class (stl/css-case :icon true - :rotated (= type :column))} i/grid-margin-refactor] - [:> numeric-input* {:placeholder "0" - :on-change (handle-change :params :margin) - :nillable true - :className (stl/css :numeric-input) - :value (or (:margin params) 0)}]] - - [:button {:class (stl/css-case :show-more-options true - :selected show-more-options?) - :on-click toggle-more-options} - i/menu-refactor] - (when show-more-options? - [:div {:class (stl/css :more-options)} - [:button {:disabled is-default - :class (stl/css :option-btn) - :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] - [:button {:disabled is-default - :class (stl/css :option-btn) - :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]])]])])] - - [:div.grid-option - [:div.grid-option-main {:style {:display (when open? "none")}} - [:button.custom-button {:class (when open? "is-active") - :on-click toggle-advanced-options} i/actions] + [:div {:class (stl/css :grid-option)} + [:div {:class (stl/css :grid-title)} + [:div {:class (stl/css-case :option-row true + :hidden is-hidden?)} + [:button {:class (stl/css-case :show-options true + :selected open?) + :on-click toggle-advanced-options} + i/menu-refactor] + [:div {:class (stl/css :type-select-wrapper)} [:& select - {:class "flex-grow" + {:class (stl/css :grid-type-select) :default-value type :options [{:value :square :label (tr "workspace.options.grid.square")} {:value :column :label (tr "workspace.options.grid.column")} {:value :row :label (tr "workspace.options.grid.row")}] - :on-change handle-change-type}] - - (if (= type :square) - [:div.input-element.pixels {:title (tr "workspace.options.size")} - [:> numeric-input* {:min 0.01 - :value (or (:size params) "") - :no-validate true - :on-change (handle-change :params :size)}]] + :on-change handle-change-type}]] + (if (= type :square) + [:div {:class (stl/css :grid-size) + :title (tr "workspace.options.size")} + [:> numeric-input* {:min 0.01 + :value (or (:size params) "") + :no-validate true + :className (stl/css :numeric-input) + :on-change (handle-change :params :size)}]] + [:div {:class (stl/css :editable-select-wrapper)} [:& editable-select {:value (:size params) :type "number" - :class "input-option" + :class (stl/css :column-select) + :input-class (stl/css :numeric-input) :min 1 :options size-options :placeholder "Auto" - :on-change handle-change-size}]) + :on-change handle-change-size}]])] - [:div.grid-option-main-actions - [:button.custom-button {:on-click handle-toggle-visibility} (if display i/eye i/eye-closed)] - [:button.custom-button {:on-click on-remove} i/minus]]] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click handle-toggle-visibility} + (if display i/shown-refactor i/hide-refactor)] + [:button {:class (stl/css :action-btn) + :on-click on-remove} + i/remove-refactor]]] - [:& advanced-options {:visible? open? :on-close toggle-advanced-options} - [:button.custom-button {:on-click toggle-advanced-options} i/actions] + (when (:display grid) + [:& advanced-options {:class (stl/css :grid-advanced-options) + :visible? open? + :on-close toggle-advanced-options} + ;; square (when (= :square type) - [:& input-row {:label (tr "workspace.options.grid.params.size") - :class "pixels" - :min 0.01 - :value (:size params) - :on-change (handle-change :params :size)}]) + [:div {:class (stl/css :square-row)} + [:div {:class (stl/css :advanced-row)} + [:& color-row {:color (:color params) + :title (tr "workspace.options.grid.params.color") + :disable-gradient true + :disable-image true + :on-change handle-change-color + :on-detach handle-detach-color}] + [:button {:class (stl/css-case :show-more-options true + :selected show-more-options?) + :on-click toggle-more-options} + i/menu-refactor]] + (when show-more-options? + [:div {:class (stl/css :second-row)} + [:button {:class (stl/css-case :btn-options true + :disabled is-default) + :disabled is-default + :on-click handle-use-default} + [:span (tr "workspace.options.grid.params.use-default")]] + [:button {:class (stl/css-case :btn-options true + :disabled is-default) + :disabled is-default + :on-click handle-set-as-default} + [:span (tr "workspace.options.grid.params.set-default")]]])]) - (when (= :row type) - [:& input-row {:label (tr "workspace.options.grid.params.rows") - :type :editable-select - :options size-options - :value (:size params) - :min 1 - :placeholder "Auto" - :on-change handle-change-size}]) - - (when (= :column type) - [:& input-row {:label (tr "workspace.options.grid.params.columns") - :type :editable-select - :options size-options - :value (:size params) - :min 1 - :placeholder "Auto" - :on-change handle-change-size}]) - - (when (#{:row :column} type) - [:& input-row {:label (tr "workspace.options.grid.params.type") - :type :select + (when (or (= :column type) (= :row type)) + [:div {:class (stl/css :column-row)} + [:div {:class (stl/css :advanced-row)} + [:div {:class (stl/css :orientation-select-wrapper)} + [:& select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :default-value (:type params) + :class (stl/css :orientation-select) :options [{:value :stretch :label (tr "workspace.options.grid.params.type.stretch")} {:value :left :label (if (= type :row) (tr "workspace.options.grid.params.type.top") @@ -353,56 +222,67 @@ {:value :right :label (if (= type :row) (tr "workspace.options.grid.params.type.bottom") (tr "workspace.options.grid.params.type.right"))}] - :value (:type params) - :on-change (handle-change :params :type)}]) + :on-change (handle-change :params :type)}]] - (when (#{:row :column} type) - [:& input-row-v2 - {:class "pixels" - :label (if (= :row type) - (tr "workspace.options.grid.params.height") - (tr "workspace.options.grid.params.width"))} - [:> numeric-input* - {:placeholder "Auto" - :value (or (:item-length params) "") - :nillable true - :on-change handle-change-item-length}]]) + [:div {:class (stl/css :color-wrapper)} + [:& color-row {:color (:color params) + :title (tr "workspace.options.grid.params.color") + :disable-gradient true + :disable-image true + :on-change handle-change-color + :on-detach handle-detach-color}]]] - (when (#{:row :column} type) - [:* - [:& input-row {:label (tr "workspace.options.grid.params.gutter") - :class "pixels" - :value (:gutter params) - :min 0 - :nillable true - :default 0 - :placeholder "0" - :on-change (handle-change :params :gutter)}] - [:& input-row {:label (tr "workspace.options.grid.params.margin") - :class "pixels" - :min 0 - :nillable true - :default 0 - :placeholder "0" - :value (:margin params) - :on-change (handle-change :params :margin)}]]) + [:div {:class (stl/css :advanced-row)} + [:div {:class (stl/css :height) + :title (if (= :row type) + (tr "workspace.options.grid.params.height") + (tr "workspace.options.grid.params.width"))} + [:span {:class (stl/css :icon-text)} + (if (= :row type) + "H" + "W")] + [:> numeric-input* {:placeholder "Auto" + :on-change handle-change-item-length + :nillable true + :className (stl/css :numeric-input) + :value (or (:item-length params) "")}]] - [:& color-row {:color (:color params) - :title (tr "workspace.options.grid.params.color") - :disable-gradient true - :disable-image true - :on-change handle-change-color - :on-detach handle-detach-color}] - [:div.row-flex - [:button.btn-options {:disabled is-default - :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] - [:button.btn-options {:disabled is-default - :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]]]]))) + [:div {:class (stl/css :gutter) + :title (tr "workspace.options.grid.params.gutter")} + [:span {:class (stl/css-case :icon true + :rotated (= type :row))} i/gap-horizontal-refactor] + [:> numeric-input* {:placeholder "0" + :on-change (handle-change :params :gutter) + :nillable true + :className (stl/css :numeric-input) + :value (or (:gutter params) 0)}]] + + [:div {:class (stl/css :margin) + :title (tr "workspace.options.grid.params.margin")} + [:span {:class (stl/css-case :icon true + :rotated (= type :column))} i/grid-margin-refactor] + [:> numeric-input* {:placeholder "0" + :on-change (handle-change :params :margin) + :nillable true + :className (stl/css :numeric-input) + :value (or (:margin params) 0)}]] + + [:button {:class (stl/css-case :show-more-options true + :selected show-more-options?) + :on-click toggle-more-options} + i/menu-refactor] + (when show-more-options? + [:div {:class (stl/css :more-options)} + [:button {:disabled is-default + :class (stl/css :option-btn) + :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] + [:button {:disabled is-default + :class (stl/css :option-btn) + :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]])]])])])) (mf/defc frame-grid [{:keys [shape]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - state* (mf/use-state true) + (let [state* (mf/use-state true) open? (deref state*) frame-grids (:grids shape) has-frame-grids? (or (= :multiple frame-grids) (some? (seq frame-grids))) @@ -413,44 +293,26 @@ default-grid-params (mf/use-memo (mf/deps saved-grids) #(merge dw/default-grid-params saved-grids)) handle-create-grid (mf/use-fn (mf/deps id) #(st/emit! (dw/add-frame-grid id)))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:& title-bar {:collapsable? has-frame-grids? - :collapsed? (not open?) - :on-collapsed toggle-content - :class (stl/css-case :title-spacing-board-grid (not has-frame-grids?)) - :title (tr "workspace.options.guides.title")} + [:div {:class (stl/css :element-set)} + [:& title-bar {:collapsable? has-frame-grids? + :collapsed? (not open?) + :on-collapsed toggle-content + :class (stl/css-case :title-spacing-board-grid (not has-frame-grids?)) + :title (tr "workspace.options.guides.title")} - [:button {:on-click handle-create-grid - :class (stl/css :add-grid)} - i/add-refactor]] + [:button {:on-click handle-create-grid + :class (stl/css :add-grid)} + i/add-refactor]] - (when (and open? (seq frame-grids)) - [:div {:class (stl/css :element-set-content)} - (for [[index grid] (map-indexed vector frame-grids)] - [:& grid-options {:key (str id "-" index) - :shape-id id - :grid grid - :index index - :frame-width (:width shape) - :frame-height (:height shape) - :default-grid-params default-grid-params}])])] - - - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.options.grid.grid-title")] - [:div.add-page {:on-click handle-create-grid} i/close]] - - (when (seq frame-grids) - [:div.element-set-content - (for [[index grid] (map-indexed vector frame-grids)] - [:& grid-options {:key (str id "-" index) - :shape-id id - :grid grid - :index index - :frame-width (:width shape) - :frame-height (:height shape) - :default-grid-params default-grid-params}])])]))) + (when (and open? (seq frame-grids)) + [:div {:class (stl/css :element-set-content)} + (for [[index grid] (map-indexed vector frame-grids)] + [:& grid-options {:key (str id "-" index) + :shape-id id + :grid grid + :index index + :frame-width (:width shape) + :frame-height (:height shape) + :default-grid-params default-grid-params}])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss index 0435242e82..4a23132e71 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss @@ -8,241 +8,250 @@ .element-set { margin: 0; - .title-spacing-board-grid { - padding-left: $s-2; - margin: 0; +} + +.title-spacing-board-grid { + padding-left: $s-2; + margin: 0; +} + +.add-grid { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; } - .add-grid { - @extend .button-tertiary; +} + +.element-set-content { + @include flexColumn; + margin: $s-4 0 $s-8 0; +} + +.grid-title { + @include flexRow; +} + +.option-row { + display: flex; + align-items: center; + gap: $s-1; + border-radius: $br-8; + background-color: var(--input-details-color); + .show-options { + @extend .button-secondary; height: $s-32; width: $s-28; + border-radius: $br-8 0 0 $br-8; + box-sizing: border-box; + border: $s-1 solid var(--input-background-color); svg { @extend .button-icon; } + &.selected { + @extend .button-icon-selected; + } } - .element-set-content { - @include flexColumn; - margin: $s-4 0 $s-8 0; - .grid-option { - .grid-title { - @include flexRow; - .option-row { - display: flex; - align-items: center; - gap: $s-1; - border-radius: $br-8; - background-color: var(--input-details-color); - .show-options { - @extend .button-secondary; - height: $s-32; - width: $s-28; - border-radius: $br-8 0 0 $br-8; - box-sizing: border-box; - border: $s-1 solid var(--input-background-color); - svg { - @extend .button-icon; - } - &.selected { - @extend .button-icon-selected; - } - } - .type-select-wrapper { - width: $s-96; - padding: 0; - border-radius: 0; - height: $s-32; - .grid-type-select { - border-radius: 0; - height: 100%; - box-sizing: border-box; - border: $s-1 solid var(--input-background-color); - &:hover { - border: $s-1 solid var(--input-background-color-hover); - } - } - } - .grid-size { - @extend .asset-element; - width: $s-60; - margin: 0; - padding: 0; - padding-left: $s-8; - border-radius: 0 $br-8 $br-8 0; - .numeric-input { - @extend .input-base; - } - } - .editable-select-wrapper { - @extend .asset-element; - width: $s-60; - margin: 0; - padding: 0; - position: relative; - border-radius: 0 $br-8 $br-8 0; - .column-select { - height: $s-32; - border-radius: 0 $br-8 $br-8 0; - box-sizing: border-box; - border: $s-1 solid var(--input-background-color); - .numeric-input { - @extend .input-base; - margin: 0; - padding: 0; - } - span { - @include flexCenter; - svg { - @extend .button-icon; - } - } - } - } - - &.hidden { - .show-options { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - } - .type-select-wrapper, - .editable-select-wrapper { - @include hiddenElement; - .column-select, - .grid-type-select { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - } - .column-select { - @include hiddenElement; - border-radius: 0 $br-8 $br-8 0; - .numeric-input { - @include hiddenElement; - } - } - } - .grid-size { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - .icon { - stroke: var(--input-foreground-color-disabled); - } - .numeric-input { - color: var(--input-foreground-color-disabled); - } - } - .actions { - .hidden-btn, - .lock-btn { - background-color: transparent; - svg { - stroke: var(--input-foreground-color-disabled); - } - } - } - } - } - - .actions { - @include flexRow; - .action-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } + .type-select-wrapper { + width: $s-96; + padding: 0; + border-radius: 0; + height: $s-32; + .grid-type-select { + border-radius: 0; + height: 100%; + box-sizing: border-box; + border: $s-1 solid var(--input-background-color); + &:hover { + border: $s-1 solid var(--input-background-color-hover); + } + } + } + .grid-size { + @extend .asset-element; + width: $s-60; + margin: 0; + padding: 0; + padding-left: $s-8; + border-radius: 0 $br-8 $br-8 0; + .numeric-input { + @extend .input-base; + } + } + .editable-select-wrapper { + @extend .asset-element; + width: $s-60; + margin: 0; + padding: 0; + position: relative; + border-radius: 0 $br-8 $br-8 0; + .column-select { + height: $s-32; + border-radius: 0 $br-8 $br-8 0; + box-sizing: border-box; + border: $s-1 solid var(--input-background-color); + .numeric-input { + @extend .input-base; + margin: 0; + padding: 0; + } + span { + @include flexCenter; + svg { + @extend .button-icon; } } } - .grid-advanced-options { - @include flexColumn; - margin-top: $s-4; - .column-row, - .square-row { - @include flexColumn; - position: relative; - .advanced-row { - position: relative; - display: flex; - gap: $s-4; - .orientation-select-wrapper { - width: $s-92; - padding: 0; - } - .color-wrapper { - width: $s-156; - } - .show-more-options { - @extend .button-tertiary; - height: $s-32; - width: $s-32; - svg { - @extend .button-icon; - } - &.selected { - @extend .button-icon-selected; - } - } - .height { - @extend .input-element; - width: $s-108; - .icon-text { - padding-top: $s-1; - } - } - .gutter, - .margin { - @extend .input-element; - width: $s-108; - .icon { - &.rotated svg { - transform: rotate(90deg); - } - } - } - .more-options { - @include menuShadow; - @include flexColumn; - position: absolute; - top: calc($s-2 + $s-28); - right: 0; - width: $s-156; - max-height: $s-300; - padding: $s-2; - margin: 0 0 $s-40 0; - margin-top: $s-4; - border-radius: $br-8; - z-index: $z-index-3; - overflow-y: auto; - background-color: var(--menu-background-color); - .option-btn { - @include buttonStyle; - display: flex; - align-items: center; - height: $s-32; - padding: 0 $s-8; - border-radius: $br-6; - color: var(--menu-foreground-color); + } - &:hover { - background-color: var(--menu-background-color-hover); - color: var(--menu-foreground-color-hover); - } - } - } + &.hidden { + .show-options { + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); + } + .type-select-wrapper, + .editable-select-wrapper { + @include hiddenElement; + .column-select, + .grid-type-select { + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); + } + .column-select { + @include hiddenElement; + border-radius: 0 $br-8 $br-8 0; + .numeric-input { + @include hiddenElement; } - .second-row { - @extend .dropdown-wrapper; - left: unset; - right: 0; - width: $s-108; - .btn-options { - @include buttonStyle; - @extend .dropdown-element-base; - width: 100%; - } + } + } + .grid-size { + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); + .icon { + stroke: var(--input-foreground-color-disabled); + } + .numeric-input { + color: var(--input-foreground-color-disabled); + } + } + .actions { + .hidden-btn, + .lock-btn { + background-color: transparent; + svg { + stroke: var(--input-foreground-color-disabled); } } } } } + +.actions { + @include flexRow; +} + +.action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.grid-advanced-options { + @include flexColumn; + margin-top: $s-4; +} + +.column-row, +.square-row { + @include flexColumn; + position: relative; +} + +.advanced-row { + position: relative; + display: flex; + gap: $s-4; + .orientation-select-wrapper { + width: $s-92; + padding: 0; + } + .color-wrapper { + width: $s-156; + } + .show-more-options { + @extend .button-tertiary; + height: $s-32; + width: $s-32; + svg { + @extend .button-icon; + } + &.selected { + @extend .button-icon-selected; + } + } + .height { + @extend .input-element; + width: $s-108; + .icon-text { + padding-top: $s-1; + } + } + .gutter, + .margin { + @extend .input-element; + width: $s-108; + .icon { + &.rotated svg { + transform: rotate(90deg); + } + } + } + + .more-options { + @include menuShadow; + @include flexColumn; + position: absolute; + top: calc($s-2 + $s-28); + right: 0; + width: $s-156; + max-height: $s-300; + padding: $s-2; + margin: 0 0 $s-40 0; + margin-top: $s-4; + border-radius: $br-8; + z-index: $z-index-3; + overflow-y: auto; + background-color: var(--menu-background-color); + .option-btn { + @include buttonStyle; + display: flex; + align-items: center; + height: $s-32; + padding: 0 $s-8; + border-radius: $br-6; + color: var(--menu-foreground-color); + + &:hover { + background-color: var(--menu-background-color-hover); + color: var(--menu-foreground-color-hover); + } + } + } +} + +.second-row { + @extend .dropdown-wrapper; + left: unset; + right: 0; + width: $s-108; + .btn-options { + @include buttonStyle; + @extend .dropdown-element-base; + width: 100%; + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs index ffd4f82d6f..7d9da91219 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs @@ -18,10 +18,8 @@ [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] - [app.main.ui.workspace.sidebar.options.menus.layout-container :as lyc] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -38,9 +36,7 @@ (mf/defc set-self-alignment [{:keys [is-col? alignment set-alignment] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - dir-v [:auto :start :center :end :stretch #_:baseline] - alignment (or alignment :auto) + (let [alignment (or alignment :auto) type (if is-col? "col" "row") handle-set-alignment @@ -49,8 +45,7 @@ (fn [value] (set-alignment (-> value keyword))))] - (if new-css-system - [:div {:class (stl/css :self-align-menu)} + [:div {:class (stl/css :self-align-menu)} [:& radio-buttons {:selected (d/name alignment) :on-change handle-set-alignment :name (dm/str "flex-align-items-" type)} @@ -72,27 +67,14 @@ [:& radio-button {:value "stretch" :icon (if is-col? i/align-self-row-strech i/align-self-column-strech) :title "Align self stretch" - :id (dm/str "align-self-stretch-" type)}]]] - - [:div.align-self-style - (for [align dir-v] - [:button.align-self.tooltip.tooltip-bottom - {:class (dom/classnames :active (= alignment align) - :tooltip-bottom-left (not= align :start) - :tooltip-bottom (= align :start)) - :alt (dm/str "Align self " (d/name align)) ;; TODO fix this tooltip - :on-click #(set-alignment align) - :key (str "align-self" align)} - (lyc/get-layout-flex-icon :align-self align is-col?)])]))) + :id (dm/str "align-self-stretch-" type)}]]])) (mf/defc options {::mf/wrap [mf/memo]} [{:keys [shape cell cells] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - state* (mf/use-state {:open true}) + (let [state* (mf/use-state {:open true}) open? (:open @state*) cells (hooks/use-equal-memo cells) @@ -181,208 +163,104 @@ (dwge/clear-selection (:id shape)))))] - (if new-css-system - [:div {:class (stl/css :grid-cell-menu)} - [:div {:class (stl/css :grid-cell-menu-title)} - [:& title-bar {:collapsable? true - :collapsed? (not open?) - :on-collapsed #(swap! state* update :open not) - :title "Grid cell"}]] + [:div {:class (stl/css :grid-cell-menu)} + [:div {:class (stl/css :grid-cell-menu-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed #(swap! state* update :open not) + :title "Grid cell"}]] - (when open? - [:div {:class (stl/css :grid-cell-menu-container)} - [:div {:class (stl/css :cell-mode :row)} - [:& radio-buttons {:selected (d/name cell-mode) - :on-change set-cell-mode - :name "cell-mode" - :wide true} - [:& radio-button {:value "auto" :id :auto}] - [:& radio-button {:value "manual" :id :manual}] - [:& radio-button {:value "area" :id :area}]]] - - (when (= :area cell-mode) - [:div {:class (stl/css :row)} - [:input - {:class (stl/css :area-input) - :key (dm/str "name-" (:id cell)) - :id "grid-area-name" - :type "text" - :aria-label "grid-area-name" - :placeholder "Area name" - :default-value area-name - :auto-complete "off" - :on-change on-area-name-change}]]) - - (when (and (not multiple?) (= :auto cell-mode)) - [:div {:class (stl/css :row)} - [:div {:class (stl/css :grid-coord-group)} - [:span {:class (stl/css :icon)} i/flex-vertical-refactor] - [:div {:class (stl/css :coord-input)} - [:> numeric-input* - {:placeholder "--" - :title "Column" - :on-click #(dom/select-target %) - :on-change (partial on-grid-coordinates :all :column) - :value column}]]] - - [:div {:class (stl/css :grid-coord-group)} - [:span {:class (stl/css :icon)} i/flex-horizontal-refactor] - [:div {:class (stl/css :coord-input)} - [:> numeric-input* - {:placeholder "--" - :title "Row" - :on-click #(dom/select-target %) - :on-change (partial on-grid-coordinates :all :row) - :value row}]]]]) - - (when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode))) - [:div {:class (stl/css :row)} - [:div {:class (stl/css :grid-coord-group)} - [:span {:class (stl/css :icon)} i/layout-rows] - [:div {:class (stl/css :coord-input)} - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :start :column) - :value column}]] - [:div {:class (stl/css :coord-input)} - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :end :column) - :value column-end}]]] - - [:div {:class (stl/css :grid-coord-group)} - [:span {:class (stl/css :icon)} i/layout-columns] - [:div {:class (stl/css :coord-input :double)} - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :start :row) - :value row}]] - [:div {:class (stl/css :coord-input)} - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :end :row) - :value row-end}]]]]) + (when open? + [:div {:class (stl/css :grid-cell-menu-container)} + [:div {:class (stl/css :cell-mode :row)} + [:& radio-buttons {:selected (d/name cell-mode) + :on-change set-cell-mode + :name "cell-mode" + :wide true} + [:& radio-button {:value "auto" :id :auto}] + [:& radio-button {:value "manual" :id :manual}] + [:& radio-button {:value "area" + :id :area + :disabled (not valid-area-cells?)}]]] + (when (= :area cell-mode) [:div {:class (stl/css :row)} - [:& set-self-alignment {:is-col? false - :alignment align-self - :set-alignment set-alignment}] - [:& set-self-alignment {:is-col? true - :alignment justify-self - :set-alignment set-justify-self}]] + [:input + {:class (stl/css :area-input) + :key (dm/str "name-" (:id cell)) + :id "grid-area-name" + :type "text" + :aria-label "grid-area-name" + :placeholder "Area name" + :default-value area-name + :auto-complete "off" + :on-change on-area-name-change}]]) + (when (and (not multiple?) (= :auto cell-mode)) [:div {:class (stl/css :row)} - [:button - {:class (stl/css :edit-grid-btn) - :alt (tr "workspace.layout_grid.editor.options.edit-grid") - :on-click toggle-edit-mode} - (tr "workspace.layout_grid.editor.options.edit-grid")]]])] + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/flex-vertical-refactor] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :title "Column" + :on-click #(dom/select-target %) + :on-change (partial on-grid-coordinates :all :column) + :value column}]]] + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/flex-horizontal-refactor] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :title "Row" + :on-click #(dom/select-target %) + :on-change (partial on-grid-coordinates :all :row) + :value row}]]]]) - [:div.element-set - [:div.element-set-title - [:span "Grid Cell"]] + (when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode))) + [:div {:class (stl/css :row)} + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/layout-rows] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :start :column) + :value column}]] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :end :column) + :value column-end}]]] - [:div.element-set-content.layout-grid-item-menu - [:div.layout-row - [:div.row-title.sizing "Position"] - [:div.position-wrapper - [:button.position-btn - {:on-click #(set-cell-mode :auto) - :class (dom/classnames :active (= :auto cell-mode))} "Auto"] - (when-not multiple? - [:button.position-btn - {:on-click #(set-cell-mode :manual) - :class (dom/classnames :active (= :manual cell-mode))} "Manual"]) - [:button.position-btn - {:on-click #(set-cell-mode :area) - :disabled (not valid-area-cells?) - :class (dom/classnames :active (= :area cell-mode))} "Area"]]] + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/layout-columns] + [:div {:class (stl/css :coord-input :double)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :start :row) + :value row}]] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :end :row) + :value row-end}]]]]) - [:div.manage-grid-columns - (when (and (not multiple?) (= :auto cell-mode)) - [:div.grid-auto - [:div.grid-columns-auto - [:span.icon i/layout-rows] - [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-click #(dom/select-target %) - :on-change (partial on-grid-coordinates :all :column) - :value column}]]] - [:div.grid-rows-auto - [:span.icon i/layout-columns] - [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-click #(dom/select-target %) - :on-change (partial on-grid-coordinates :all :row) - :value row}]]]]) + [:div {:class (stl/css :row)} + [:& set-self-alignment {:is-col? false + :alignment align-self + :set-alignment set-alignment}] + [:& set-self-alignment {:is-col? true + :alignment justify-self + :set-alignment set-justify-self}]] - (when (= :area cell-mode) - [:div.input-wrapper - [:input.input-text - {:key (dm/str "name-" (:id cell)) - :id "grid-area-name" - :type "text" - :aria-label "grid-area-name" - :placeholder "--" - :default-value area-name - :auto-complete "off" - :on-change on-area-name-change}]]) - - (when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode))) - [:div.grid-manual - [:div.grid-columns-auto - [:span.icon i/layout-rows] - [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :start :column) - :value column}] - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :end :column) - :value column-end}]]] - [:div.grid-rows-auto - [:span.icon i/layout-columns] - [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :start :row) - :value row}] - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :end :row) - :value row-end}]]]])] - - [:div.layout-row - [:div.row-title "Align"] - [:div.btn-wrapper - [:& set-self-alignment {:is-col? false - :alignment align-self - :set-alignment set-alignment}]]] - [:div.layout-row - [:div.row-title "Justify"] - [:div.btn-wrapper - [:& set-self-alignment {:is-col? true - :alignment justify-self - :set-alignment set-justify-self}]]] - - [:div.layout-row.single-button - [:div.btn-wrapper - [:div.edit-mode - [:button.tooltip.tooltip-bottom-left - {:alt "Grid edit mode" - :on-click toggle-edit-mode - :style {:padding 0}} - "Edit grid" - i/grid-layout-mode]]]]]]))) + [:div {:class (stl/css :row)} + [:button + {:class (stl/css :edit-grid-btn) + :alt (tr "workspace.layout_grid.editor.options.edit-grid") + :on-click toggle-edit-mode} + (tr "workspace.layout_grid.editor.options.edit-grid")]]])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss index 66fa82d4e6..a2a3449f4e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss @@ -6,53 +6,51 @@ @import "refactor/common-refactor.scss"; -.grid-cell-menu { - .grid-cell-menu-container { - @include flexColumn; - margin-top: $s-8; - gap: $s-16; - } +.grid-cell-menu-container { + @include flexColumn; + margin-top: $s-8; + gap: $s-16; +} - .grid-cell-menu-title { - font-size: $fs-11; - } +.grid-cell-menu-title { + font-size: $fs-11; +} - .row { - @include flexRow; - } +.row { + @include flexRow; +} - .cell-mode :global(label) { - padding: 0 $s-12; - } +.cell-mode :global(label) { + padding: 0 $s-12; +} - .edit-grid-btn { - @extend .button-secondary; - @include tabTitleTipography; - width: 100%; - padding: $s-8; - } +.edit-grid-btn { + @extend .button-secondary; + @include tabTitleTipography; + width: 100%; + padding: $s-8; +} - .area-input { - @extend .input-element; - width: 100%; - padding: $s-8; - } +.area-input { + @extend .input-element; + width: 100%; + padding: $s-8; } .grid-coord-group { @include flexRow; - border-radius: $br-8; padding-left: $s-4; background-color: var(--input-background-color); - - .icon svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - .coord-input { - @extend .input-element; - border-radius: 0 $br-8 $br-8 0; - border-left: 1px solid var(--panel-background-color); - } +} + +.icon svg { + @extend .button-icon; + stroke: var(--icon-foreground); +} + +.coord-input { + @extend .input-element; + border-radius: 0 $br-8 $br-8 0; + border-left: 1px solid var(--panel-background-color); } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index d99ca6ba1b..67138d85e0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -22,7 +22,6 @@ [app.main.ui.components.radio-buttons :refer [radio-buttons radio-button]] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -45,15 +44,6 @@ [interaction] (get (event-type-names) (:event-type interaction) "--")) -(defn- action-type-names - [] - {:navigate (tr "workspace.options.interaction-navigate-to") - :open-overlay (tr "workspace.options.interaction-open-overlay") - :toggle-overlay (tr "workspace.options.interaction-toggle-overlay") - :close-overlay (tr "workspace.options.interaction-close-overlay") - :prev-screen (tr "workspace.options.interaction-prev-screen") - :open-url (tr "workspace.options.interaction-open-url")}) - (defn- action-summary [interaction destination] (case (:action-type interaction) @@ -69,34 +59,6 @@ :open-url (tr "workspace.options.interaction-open-url") "--")) -(defn- overlay-pos-type-names - [] - {:manual (tr "workspace.options.interaction-pos-manual") - :center (tr "workspace.options.interaction-pos-center") - :top-left (tr "workspace.options.interaction-pos-top-left") - :top-right (tr "workspace.options.interaction-pos-top-right") - :top-center (tr "workspace.options.interaction-pos-top-center") - :bottom-left (tr "workspace.options.interaction-pos-bottom-left") - :bottom-right (tr "workspace.options.interaction-pos-bottom-right") - :bottom-center (tr "workspace.options.interaction-pos-bottom-center")}) - -(defn- animation-type-names - [interaction] - (cond-> - {:dissolve (tr "workspace.options.interaction-animation-dissolve") - :slide (tr "workspace.options.interaction-animation-slide")} - - (ctsi/allow-push? (:action-type interaction)) - (assoc :push (tr "workspace.options.interaction-animation-push")))) - -(defn- easing-names - [] - {:linear (tr "workspace.options.interaction-easing-linear") - :ease (tr "workspace.options.interaction-easing-ease") - :ease-in (tr "workspace.options.interaction-easing-ease-in") - :ease-out (tr "workspace.options.interaction-easing-ease-out") - :ease-in-out (tr "workspace.options.interaction-easing-ease-in-out")}) - (defn- get-frames-options [frames shape] (->> frames @@ -115,8 +77,7 @@ (mf/defc flow-item [{:keys [flow]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - editing? (mf/use-state false) + (let [editing? (mf/use-state false) flow-for-rename (mf/deref flow-for-rename-ref) name-ref (mf/use-ref) @@ -144,10 +105,10 @@ (mf/deps flow) #(st/emit! (dw/select-shape (:starting-frame flow)))) - rename-flow - (mf/use-fn - (mf/deps flow) - #(st/emit! (dwi/start-rename-flow (:id flow)))) + ;; rename-flow + ;; (mf/use-fn + ;; (mf/deps flow) + ;; #(st/emit! (dwi/start-rename-flow (:id flow)))) remove-flow (mf/use-fn @@ -171,95 +132,59 @@ (let [name-input (mf/ref-val name-ref)] (dom/select-text! name-input)) nil)) - (if new-css-system - [:div {:class (stl/css :flow-element)} - [:span {:class (stl/css :flow-info)} - [:span {:class (stl/css :flow-name-wrapper)} - [:button {:class (stl/css :start-flow-btn) - :on-click start-flow} - [:span {:class (stl/css :button-icon)} - i/play-refactor]] - [:span {:class (stl/css :flow-input-wrapper)} - [:input - {:class (stl/css :flow-input) - :type "text" - :ref name-ref - :on-blur accept-edit - :on-key-down on-key-down - :default-value (:name flow "")}]]]] - [:button {:class (stl/css :remove-flow-btn) - :on-click remove-flow} - i/remove-refactor]] + [:div {:class (stl/css :flow-element)} + [:span {:class (stl/css :flow-info)} + [:span {:class (stl/css :flow-name-wrapper)} + [:button {:class (stl/css :start-flow-btn) + :on-click start-flow} + [:span {:class (stl/css :button-icon)} + i/play-refactor]] + [:span {:class (stl/css :flow-input-wrapper)} + [:input + {:class (stl/css :flow-input) + :type "text" + :ref name-ref + :on-blur accept-edit + :on-key-down on-key-down + :default-value (:name flow "")}]]]] - [:div.flow-element - [:div.flow-button {:on-click start-flow} i/play] - (if @editing? - [:input.element-name - {:type "text" - :ref name-ref - :on-blur accept-edit - :on-key-down on-key-down - :auto-focus true - :default-value (:name flow "")}] - [:span.element-label.flow-name - {:on-double-click rename-flow} - (:name flow)]) - [:div.add-page {:on-click remove-flow} i/minus]]))) + [:button {:class (stl/css :remove-flow-btn) + :on-click remove-flow} + i/remove-refactor]])) (mf/defc page-flows [{:keys [flows]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - (when (seq flows) - [:div {:class (stl/css :interaction-options)} - [:& title-bar {:collapsable? false - :title (tr "workspace.options.flows.flow-starts") - :class (stl/css :title-spacing-layout-flow)}] - (for [flow flows] - [:& flow-item {:flow flow :key (str (:id flow))}])]) - - (when (seq flows) - [:div.element-set.interactions-options - [:div.element-set-title - [:span (tr "workspace.options.flows.flow-starts")]] - (for [flow flows] - [:& flow-item {:flow flow :key (str (:id flow))}])])))) + (when (seq flows) + [:div {:class (stl/css :interaction-options)} + [:& title-bar {:collapsable? false + :title (tr "workspace.options.flows.flow-starts") + :class (stl/css :title-spacing-layout-flow)}] + (for [flow flows] + [:& flow-item {:flow flow :key (str (:id flow))}])])) (mf/defc shape-flows [{:keys [flows shape]}] (when (= (:type shape) :frame) - (let [new-css-system (mf/use-ctx ctx/new-css-system) - flow (ctp/get-frame-flow flows (:id shape)) + (let [flow (ctp/get-frame-flow flows (:id shape)) add-flow (mf/use-fn #(st/emit! (dwi/add-flow-selected-frame)))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:& title-bar {:collapsable? false - :title (tr "workspace.options.flows.flow") - :class (stl/css :title-spacing-layout-flow)} - (when (nil? flow) - [:button {:class (stl/css :add-flow-btn) - :title (tr "workspace.options.flows.add-flow-start") - :on-click add-flow} - i/add-refactor])] - (when flow - [:& flow-item {:flow flow :key (str (:id flow))}])] + [:div {:class (stl/css :element-set)} + [:& title-bar {:collapsable? false + :title (tr "workspace.options.flows.flow") + :class (stl/css :title-spacing-layout-flow)} + (when (nil? flow) + [:button {:class (stl/css :add-flow-btn) + :title (tr "workspace.options.flows.add-flow-start") + :on-click add-flow} + i/add-refactor])] - [:div.element-set.interactions-options - [:div.element-set-title - [:span (tr "workspace.options.flows.flow-start")]] - (if (nil? flow) - [:div.flow-element - [:span.element-label (tr "workspace.options.flows.add-flow-start")] - [:div.add-page {:on-click add-flow} - i/plus]] - [:& flow-item {:flow flow :key (str (:id flow))}])])))) + (when flow + [:& flow-item {:flow flow :key (str (:id flow))}])]))) (mf/defc interaction-entry [{:keys [index shape interaction update-interaction remove-interaction]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - objects (deref refs/workspace-page-objects) + (let [objects (deref refs/workspace-page-objects) destination (get objects (:destination interaction)) frames (mf/with-memo [objects] (ctt/get-viewer-frames objects {:all-frames? true})) @@ -286,18 +211,14 @@ (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - (keyword event) - (-> event dom/get-target dom/get-value d/read-string))] + (let [value (keyword event)] (update-interaction index #(ctsi/set-event-type % value shape))))) change-action-type (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - (keyword event) - (-> event dom/get-target dom/get-value d/read-string))] + (let [value (keyword event)] (update-interaction index #(ctsi/set-action-type % value))))) change-delay @@ -310,9 +231,7 @@ (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - event - (-> event dom/get-target dom/get-value)) + (let [value event value (when (not= value "") (uuid/uuid value))] (update-interaction index #(ctsi/set-destination % value))))) @@ -320,12 +239,7 @@ (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - (uuid/uuid event) - (-> event - dom/get-target - dom/get-value - uuid/uuid))] + (let [value (uuid/uuid event)] (update-interaction index #(ctsi/set-position-relative-to % value))))) change-preserve-scroll @@ -357,11 +271,8 @@ change-overlay-pos-type (mf/use-fn (mf/deps shape) - (fn [event] - (let [shape-id (:id shape) - value (if new-css-system - event - (-> event dom/get-target dom/get-value d/read-string))] + (fn [value] + (let [shape-id (:id shape)] (update-interaction index #(ctsi/set-overlay-pos-type % value shape objects)) (when (= value :manual) (update-interaction index #(ctsi/set-position-relative-to % shape-id)))))) @@ -393,11 +304,9 @@ (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - (if (= "" event) - nil - (keyword event)) - (-> event dom/get-target dom/get-value d/read-string))] + (let [value (if (= "" event) + nil + (keyword event))] (update-interaction index #(ctsi/set-animation-type % value))))) change-duration @@ -408,30 +317,21 @@ (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - (keyword event) - (-> event dom/get-target dom/get-value d/read-string))] + (let [value (keyword event)] (update-interaction index #(ctsi/set-easing % value))))) change-way (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - (keyword event) - (-> event dom/get-target dom/get-value d/read-string))] + (let [value (keyword event)] (update-interaction index #(ctsi/set-way % value))))) change-direction (mf/use-fn (mf/deps index) (fn [event] - (let [value (if new-css-system - (keyword event) - (-> event - dom/get-target - (dom/get-data "value") - keyword))] + (let [value (keyword event)] (update-interaction index #(ctsi/set-direction % value))))) change-offset-effect @@ -502,565 +402,293 @@ {:icon :easing-ease-in-out-refactor :value :ease-in-out :label (tr "workspace.options.interaction-easing-ease-in-out")}]] - (if new-css-system - [:div {:class (stl/css-case :element-set-options-group true - :open extended-open?)} - ; Summary - [:div {:class (stl/css :interactions-summary)} - [:div {:class (stl/css-case :extend-btn true - :extended extended-open?) - :on-click toggle-extended} - i/menu-refactor] + [:div {:class (stl/css-case :element-set-options-group true + :open extended-open?)} + ; Summary + [:div {:class (stl/css :interactions-summary)} + [:div {:class (stl/css-case :extend-btn true + :extended extended-open?) + :on-click toggle-extended} + i/menu-refactor] - [:div {:class (stl/css :interactions-info) - :on-click toggle-extended} - [:div {:class (stl/css :trigger-name)} (event-type-name interaction)] - [:div {:class (stl/css :action-summary)} (action-summary interaction destination)]] - [:button {:class (stl/css :remove-btn) - :data-value index - :on-click #(remove-interaction index)} - i/remove-refactor]] + [:div {:class (stl/css :interactions-info) + :on-click toggle-extended} + [:div {:class (stl/css :trigger-name)} (event-type-name interaction)] + [:div {:class (stl/css :action-summary)} (action-summary interaction destination)]] + [:button {:class (stl/css :remove-btn) + :data-value index + :on-click #(remove-interaction index)} + i/remove-refactor]] - (when extended-open? - [:div {:class (stl/css :extended-options)} - ;; Trigger select + (when extended-open? + [:div {:class (stl/css :extended-options)} + ;; Trigger select + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} + (tr "workspace.options.interaction-trigger")] + [:div {:class (stl/css :select-wrapper)} + [:& select {:class (stl/css :interaction-type-select) + :default-value (:event-type interaction) + :options event-type-options + :on-change change-event-type}]]] + + ;; Delay + (when (ctsi/has-delay interaction) [:div {:class (stl/css :property-row)} [:span {:class (stl/css :interaction-name)} - (tr "workspace.options.interaction-trigger")] - [:div {:class (stl/css :select-wrapper)} - [:& select {:class (stl/css :interaction-type-select) - :default-value (:event-type interaction) - :options event-type-options - :on-change change-event-type}]]] + (tr "workspace.options.interaction-delay")] + [:div {:class (stl/css :input-element-wrapper) + :title (tr "workspace.options.interaction-ms")} + [:span.after (tr "workspace.options.interaction-ms")] + [:> numeric-input* {:ref ext-delay-ref + :className (stl/css :numeric-input) + :on-change change-delay + :value (:delay interaction) + :title (tr "workspace.options.interaction-ms")}]]]) - ;; Delay - (when (ctsi/has-delay interaction) - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} - (tr "workspace.options.interaction-delay")] - [:div {:class (stl/css :input-element-wrapper) - :title (tr "workspace.options.interaction-ms")} - [:span.after (tr "workspace.options.interaction-ms")] - [:> numeric-input* {:ref ext-delay-ref - :className (stl/css :numeric-input) - :on-change change-delay - :value (:delay interaction) - :title (tr "workspace.options.interaction-ms")}]]]) + ;; Action select + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-action")] + [:div {:class (stl/css :select-wrapper)} + [:& select {:class (stl/css :interaction-type-select) + :default-value (:action-type interaction) + :options action-type-options + :on-change change-action-type}]]] - ;; Action select + ;; Destination + (when (ctsi/has-destination interaction) [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-action")] + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-destination")] [:div {:class (stl/css :select-wrapper)} [:& select {:class (stl/css :interaction-type-select) - :default-value (:action-type interaction) - :options action-type-options - :on-change change-action-type}]]] + :default-value (str (:destination interaction)) + :options destination-options + :on-change change-destination}]]]) - ;; Destination - (when (ctsi/has-destination interaction) - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-destination")] - [:div {:class (stl/css :select-wrapper)} - [:& select {:class (stl/css :interaction-type-select) - :default-value (str (:destination interaction)) - :options destination-options - :on-change change-destination}]]]) + ;; Preserve scroll + (when (ctsi/has-preserve-scroll interaction) + [:div {:class (stl/css :property-row)} + [:div {:class (stl/css :checkbox-option)} + [:label {:for (str "preserve-" index) + :class (stl/css-case :global/checked preserve-scroll?)} + [:span {:class (stl/css-case :global/checked preserve-scroll?)} + (when preserve-scroll? + i/status-tick-refactor)] + (tr "workspace.options.interaction-preserve-scroll") + [:input {:type "checkbox" + :id (str "preserve-" index) + :checked preserve-scroll? + :on-change change-preserve-scroll}]]]]) - ;; Preserve scroll - (when (ctsi/has-preserve-scroll interaction) - [:div {:class (stl/css :property-row)} - [:div {:class (stl/css :checkbox-option)} - [:label {:for (str "preserve-" index) - :class (stl/css-case :global/checked preserve-scroll?)} - [:span {:class (stl/css-case :global/checked preserve-scroll?)} - (when preserve-scroll? - i/status-tick-refactor)] - (tr "workspace.options.interaction-preserve-scroll") - [:input {:type "checkbox" - :id (str "preserve-" index) - :checked preserve-scroll? - :on-change change-preserve-scroll}]]]]) + ;; URL + (when (ctsi/has-url interaction) + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-url")] + [:div {:class (stl/css :input-element-wrapper)} + [:input {:class (stl/css :input-text) + :type "url" + :placeholder "http://example.com" + :default-value (str (:url interaction)) + :on-blur change-url}]]]) - ;; URL - (when (ctsi/has-url interaction) - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-url")] - [:div {:class (stl/css :input-element-wrapper)} - [:input {:class (stl/css :input-text) - :type "url" - :placeholder "http://example.com" - :default-value (str (:url interaction)) - :on-blur change-url}]]]) + (when (ctsi/has-overlay-opts interaction) + [:* + ;; Overlay position relative-to (select) + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-relative-to")] + [:div {:class (stl/css :select-wrapper)} + [:& select {:class (stl/css :interaction-type-select) + :default-value (str (:position-relative-to interaction)) + :options relative-to-opts + :on-change change-position-relative-to}]]] - (when (ctsi/has-overlay-opts interaction) - [:* - ;; Overlay position relative-to (select) - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-relative-to")] - [:div {:class (stl/css :select-wrapper)} - [:& select {:class (stl/css :interaction-type-select) - :default-value (str (:position-relative-to interaction)) - :options relative-to-opts - :on-change change-position-relative-to}]]] + ;; Overlay position (select) + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-position")] + [:div {:class (stl/css :select-wrapper)} + [:& select {:class (stl/css :interaction-type-select) + :default-value (:overlay-pos-type interaction) + :options overlay-position-opts + :on-change change-overlay-pos-type}]]] - ;; Overlay position (select) - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-position")] - [:div {:class (stl/css :select-wrapper)} - [:& select {:class (stl/css :interaction-type-select) - :default-value (:overlay-pos-type interaction) - :options overlay-position-opts - :on-change change-overlay-pos-type}]]] + ;; Overlay position (buttons) + [:div {:class (stl/css-case :property-row true + :big-row true)} + [:div {:class (stl/css :position-btns-wrapper)} + [:button {:class (stl/css-case :direction-btn true + :center-btn true + :active (= overlay-pos-type :center)) + :data-value :center + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :top-left-btn true + :active (= overlay-pos-type :top-left)) + :data-value :top-left + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :top-right-btn true + :active (= overlay-pos-type :top-right)) + :data-value :top-right + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] - ;; Overlay position (buttons) - [:div {:class (stl/css-case :property-row true - :big-row true)} - [:div {:class (stl/css :position-btns-wrapper)} - [:button {:class (stl/css-case :direction-btn true - :center-btn true - :active (= overlay-pos-type :center)) - :data-value :center - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] - [:button {:class (stl/css-case :direction-btn true - :top-left-btn true - :active (= overlay-pos-type :top-left)) - :data-value :top-left - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] - [:button {:class (stl/css-case :direction-btn true - :top-right-btn true - :active (= overlay-pos-type :top-right)) - :data-value :top-right - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :top-center-btn true + :active (= overlay-pos-type :top-center)) + :data-value :top-center + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :bottom-left-btn true + :active (= overlay-pos-type :bottom-left)) + :data-value :bottom-left + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :bottom-left-btn true + :active (= overlay-pos-type :bottom-left)) + :data-value :bottom-left + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] - [:button {:class (stl/css-case :direction-btn true - :top-center-btn true - :active (= overlay-pos-type :top-center)) - :data-value :top-center - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] - [:button {:class (stl/css-case :direction-btn true - :bottom-left-btn true - :active (= overlay-pos-type :bottom-left)) - :data-value :bottom-left - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] - [:button {:class (stl/css-case :direction-btn true - :bottom-left-btn true - :active (= overlay-pos-type :bottom-left)) - :data-value :bottom-left - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :bottom-left-btn true + :active (= overlay-pos-type :bottom-left)) + :data-value :bottom-left + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :bottom-right-btn true + :active (= overlay-pos-type :bottom-right)) + :data-value :bottom-right + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]] + [:button {:class (stl/css-case :direction-btn true + :bottom-center-btn true + :active (= overlay-pos-type :bottom-center)) + :data-value :bottom-center + :on-click toggle-overlay-pos-type} + [:span {:class (stl/css :rectangle)}]]]] - [:button {:class (stl/css-case :direction-btn true - :bottom-left-btn true - :active (= overlay-pos-type :bottom-left)) - :data-value :bottom-left - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] - [:button {:class (stl/css-case :direction-btn true - :bottom-right-btn true - :active (= overlay-pos-type :bottom-right)) - :data-value :bottom-right - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] - [:button {:class (stl/css-case :direction-btn true - :bottom-center-btn true - :active (= overlay-pos-type :bottom-center)) - :data-value :bottom-center - :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]]]] - - ;; Overlay click outside - [:div {:class (stl/css :property-row)} - [:div {:class (stl/css :checkbox-option)} - [:label {:for (str "close-" index) - :class (stl/css-case :global/checked close-click-outside?)} - [:span {:class (stl/css-case :global/checked close-click-outside?)} - (when close-click-outside? - i/status-tick-refactor)] - (tr "workspace.options.interaction-close-outside") - [:input {:type "checkbox" - :id (str "close-" index) - :checked close-click-outside? - :on-change change-close-click-outside}]]]] - - ;; Overlay background - [:div {:class (stl/css :property-row)} - [:div {:class (stl/css :checkbox-option)} - [:label {:for (str "background-" index) - :class (stl/css-case :global/checked background-overlay?)} - [:span {:class (stl/css-case :global/checked background-overlay?)} - (when background-overlay? - i/status-tick-refactor)] - (tr "workspace.options.interaction-background") - [:input {:type "checkbox" - :id (str "background-" index) - :checked background-overlay? - :on-change change-background-overlay}]]]]]) - - (when (ctsi/has-animation? interaction) - [:* - ;; Animation select - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-animation")] - [:div {:class (stl/css :select-wrapper)} - [:& select {:class (stl/css :animation-select) - :default-value (or (-> interaction :animation :animation-type) "") - :options animation-opts - :on-change change-animation-type}]]] - - ;; Direction - (when (ctsi/has-way? interaction) - [:div {:class (stl/css :property-row)} - [:div {:class (stl/css :inputs-wrapper)} - - [:& radio-buttons {:selected (d/name way) - :on-change change-way - :name "animation-way"} - [:& radio-button {:value "in" - :id "animation-way-in"}] - [:& radio-button {:id "animation-way-out" - :value "out"}]]]]) - - ;; Direction - (when (ctsi/has-direction? interaction) - [:div {:class (stl/css :property-row)} - [:div {:class (stl/css :buttons-wrapper)} - [:& radio-buttons {:selected (d/name direction) - :on-change change-direction - :name "animation-direction"} - [:& radio-button {:icon i/column-refactor - :icon-class (stl/css :right) - :value "right" - :id "animation-right"}] - [:& radio-button {:icon i/column-refactor - :icon-class (stl/css :left) - :id "animation-left" - :value "left"}] - [:& radio-button {:icon i/column-refactor - :icon-class (stl/css :down) - :id "animation-down" - :value "down"}] - [:& radio-button {:icon i/column-refactor - :icon-class (stl/css :up) - :id "animation-up" - :value "up"}]]]]) - - ;; Duration - (when (ctsi/has-duration? interaction) - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-duration")] - [:div {:class (stl/css :input-element-wrapper) - :title (tr "workspace.options.interaction-ms")} - [:span.after (tr "workspace.options.interaction-ms")] - [:> numeric-input* {:ref ext-duration-ref - :on-change change-duration - :value (-> interaction :animation :duration) - :title (tr "workspace.options.interaction-ms")}]]]) - - ;; Easing - (when (ctsi/has-easing? interaction) - [:div {:class (stl/css :property-row)} - [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-easing")] - [:div {:class (stl/css :select-wrapper)} - [:& select {:class (stl/css :easing-select) - :dropdown-class (stl/css :dropdown-upwards) - :default-value (-> interaction :animation :easing) - :options easing-options - :on-change change-easing}]]]) - - ;; Offset effect - (when (ctsi/has-offset-effect? interaction) - [:div {:class (stl/css :property-row)} - [:div {:class (stl/css :checkbox-option)} - [:label {:for (str "offset-effect-" index) - :class (stl/css-case :global/checked (-> interaction :animation :offset-effect))} - [:span {:class (stl/css-case :global/checked (-> interaction :animation :offset-effect))} - (when (-> interaction :animation :offset-effect) - i/status-tick-refactor)] - (tr "workspace.options.interaction-offset-effect") - [:input {:type "checkbox" - :id (str "offset-effect-" index) - :checked (-> interaction :animation :offset-effect) - :on-change change-offset-effect}]]]])])])] - - - [:div.element-set-options-group {:class (dom/classnames - :open extended-open?)} - ; Summary - [:div.element-set-actions-button {:on-click toggle-extended} - i/actions] - [:div.interactions-summary {:on-click toggle-extended} - [:div.trigger-name (event-type-name interaction)] - [:div.action-summary (action-summary interaction destination)]] - [:div.element-set-actions {:on-click #(remove-interaction index)} - [:div.element-set-actions-button i/minus]] - - (when extended-open? - [:div.element-set-content - - ;; Trigger select - [:div.interactions-element.separator - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-trigger")] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (str (:event-type interaction)) - :on-change change-event-type} - (for [[value name] (event-type-names)] - (when-not (and (= value :after-delay) - (not= (:type shape) :frame)) - [:option {:key (dm/str value) - :value (dm/str value)} name]))]] - - ;; Delay - (when (ctsi/has-delay interaction) - [:div.interactions-element - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-delay")] - [:div.input-element {:title (tr "workspace.options.interaction-ms")} - [:> numeric-input* {:ref ext-delay-ref - :on-change change-delay - :value (:delay interaction) - :title (tr "workspace.options.interaction-ms")}] - [:span.after (tr "workspace.options.interaction-ms")]]]) - - ;; Action select - [:div.interactions-element.separator - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-action")] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (str (:action-type interaction)) - :on-change change-action-type} - (for [[value name] (action-type-names)] - [:option {:key (dm/str "action-" value) - :value (str value)} name])]] - - ;; Destination - (when (ctsi/has-destination interaction) - [:div.interactions-element - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-destination")] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (str (:destination interaction)) - :on-change change-destination} - (if (= (:action-type interaction) :close-overlay) - [:option {:value ""} (tr "workspace.options.interaction-self")] - [:option {:value ""} (tr "workspace.options.interaction-none")]) - (for [frame frames] - (when (and (not= (:id frame) (:id shape)) ; A frame cannot navigate to itself - (not= (:id frame) (:frame-id shape))) ; nor a shape to its container frame - [:option {:key (dm/str "destination-" (:id frame)) - :value (str (:id frame))} (:name frame)]))]]) - - ;; Preserve scroll - (when (ctsi/has-preserve-scroll interaction) - [:div.interactions-element - [:div.input-checkbox + ;; Overlay click outside + [:div {:class (stl/css :property-row)} + [:div {:class (stl/css :checkbox-option)} + [:label {:for (str "close-" index) + :class (stl/css-case :global/checked close-click-outside?)} + [:span {:class (stl/css-case :global/checked close-click-outside?)} + (when close-click-outside? + i/status-tick-refactor)] + (tr "workspace.options.interaction-close-outside") [:input {:type "checkbox" - :id (str "preserve-" index) - :checked preserve-scroll? - :on-change change-preserve-scroll}] - [:label {:for (str "preserve-" index)} - (tr "workspace.options.interaction-preserve-scroll")]]]) + :id (str "close-" index) + :checked close-click-outside? + :on-change change-close-click-outside}]]]] - ;; URL - (when (ctsi/has-url interaction) - [:div.interactions-element - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-url")] - [:input.input-text {:type "url" - :placeholder "http://example.com" - :default-value (str (:url interaction)) - :on-blur change-url}]]) + ;; Overlay background + [:div {:class (stl/css :property-row)} + [:div {:class (stl/css :checkbox-option)} + [:label {:for (str "background-" index) + :class (stl/css-case :global/checked background-overlay?)} + [:span {:class (stl/css-case :global/checked background-overlay?)} + (when background-overlay? + i/status-tick-refactor)] + (tr "workspace.options.interaction-background") + [:input {:type "checkbox" + :id (str "background-" index) + :checked background-overlay? + :on-change change-background-overlay}]]]]]) - (when (ctsi/has-overlay-opts interaction) - [:* - ;; Overlay position relative-to (select) - [:div.interactions-element - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-relative-to")] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (str (:position-relative-to interaction)) - :on-change change-position-relative-to} - (when (not= (:overlay-pos-type interaction) :manual) - [:* - [:option {:value ""} (tr "workspace.options.interaction-auto")] - (for [frame shape-parents] - [:option {:key (dm/str "position-relative-to-" (:id frame)) - :value (str (:id frame))} (:name frame)])]) - [:option {:key (dm/str "position-relative-to-" (:id shape)) - :value (str (:id shape))} (:name shape) " (" (tr "workspace.options.interaction-self") ")"]]] + (when (ctsi/has-animation? interaction) + [:* + ;; Animation select + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-animation")] + [:div {:class (stl/css :select-wrapper)} + [:& select {:class (stl/css :animation-select) + :default-value (or (-> interaction :animation :animation-type) "") + :options animation-opts + :on-change change-animation-type}]]] - ;; Overlay position (select) - [:div.interactions-element - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-position")] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (str (:overlay-pos-type interaction)) - :on-change change-overlay-pos-type} - (for [[value name] (overlay-pos-type-names)] - [:option {:value (str value)} name])]] + ;; Direction + (when (ctsi/has-way? interaction) + [:div {:class (stl/css :property-row)} + [:div {:class (stl/css :inputs-wrapper)} - ;; Overlay position (buttons) - [:div.interactions-element.interactions-pos-buttons - [:div.element-set-actions-button - {:class (dom/classnames :active (= overlay-pos-type :center)) - :data-value :center - :on-click toggle-overlay-pos-type} - i/position-center] - [:div.element-set-actions-button - {:class (dom/classnames :active (= overlay-pos-type :top-left)) - :data-value :top-left - :on-click toggle-overlay-pos-type} - i/position-top-left] - [:div.element-set-actions-button - {:class (dom/classnames :active (= overlay-pos-type :top-right)) - :data-value :top-right - :on-click toggle-overlay-pos-type} - i/position-top-right] - [:div.element-set-actions-button - {:class (dom/classnames :active (= overlay-pos-type :top-center)) - :data-value :top-center - :on-click toggle-overlay-pos-type} - i/position-top-center] - [:div.element-set-actions-button - {:class (dom/classnames :active (= overlay-pos-type :bottom-left)) - :data-value :bottom-center - :on-click toggle-overlay-pos-type} - i/position-bottom-left] - [:div.element-set-actions-button - {:class (dom/classnames :active (= overlay-pos-type :bottom-right)) - :data-value :bottom-right - :on-click toggle-overlay-pos-type} - i/position-bottom-right] - [:div.element-set-actions-button - {:class (dom/classnames :active (= overlay-pos-type :bottom-center)) - :data-value :bottom-center - :on-click toggle-overlay-pos-type} - i/position-bottom-center]] + [:& radio-buttons {:selected (d/name way) + :on-change change-way + :name "animation-way"} + [:& radio-button {:value "in" + :id "animation-way-in"}] + [:& radio-button {:id "animation-way-out" + :value "out"}]]]]) - ;; Overlay click outside - [:div.interactions-element - [:div.input-checkbox - [:input {:type "checkbox" - :id (str "close-" index) - :checked close-click-outside? - :on-change change-close-click-outside}] - [:label {:for (str "close-" index)} - (tr "workspace.options.interaction-close-outside")]]] + ;; Direction + (when (ctsi/has-direction? interaction) + [:div {:class (stl/css :property-row)} + [:div {:class (stl/css :buttons-wrapper)} + [:& radio-buttons {:selected (d/name direction) + :on-change change-direction + :name "animation-direction"} + [:& radio-button {:icon i/column-refactor + :icon-class (stl/css :right) + :value "right" + :id "animation-right"}] + [:& radio-button {:icon i/column-refactor + :icon-class (stl/css :left) + :id "animation-left" + :value "left"}] + [:& radio-button {:icon i/column-refactor + :icon-class (stl/css :down) + :id "animation-down" + :value "down"}] + [:& radio-button {:icon i/column-refactor + :icon-class (stl/css :up) + :id "animation-up" + :value "up"}]]]]) - ;; Overlay background - [:div.interactions-element - [:div.input-checkbox - [:input {:type "checkbox" - :id (str "background-" index) - :checked background-overlay? - :on-change change-background-overlay}] - [:label {:for (str "background-" index)} - (tr "workspace.options.interaction-background")]]]]) + ;; Duration + (when (ctsi/has-duration? interaction) + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-duration")] + [:div {:class (stl/css :input-element-wrapper) + :title (tr "workspace.options.interaction-ms")} + [:span.after (tr "workspace.options.interaction-ms")] + [:> numeric-input* {:ref ext-duration-ref + :on-change change-duration + :value (-> interaction :animation :duration) + :title (tr "workspace.options.interaction-ms")}]]]) - (when (ctsi/has-animation? interaction) - [:* - ;; Animation select - [:div.interactions-element.separator - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-animation")] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (str (-> interaction :animation :animation-type)) - :on-change change-animation-type} - [:option {:value ""} (tr "workspace.options.interaction-animation-none")] - (for [[value name] (animation-type-names interaction)] - [:option {:value (str value)} name])]] + ;; Easing + (when (ctsi/has-easing? interaction) + [:div {:class (stl/css :property-row)} + [:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-easing")] + [:div {:class (stl/css :select-wrapper)} + [:& select {:class (stl/css :easing-select) + :dropdown-class (stl/css :dropdown-upwards) + :default-value (-> interaction :animation :easing) + :options easing-options + :on-change change-easing}]]]) - ;; Direction - (when (ctsi/has-way? interaction) - [:div.interactions-element.interactions-way-buttons - [:div.input-radio - [:input {:type "radio" - :id "way-in" - :checked (= :in way) - :name "animation-way" - :value ":in" - :on-change change-way}] - [:label {:for "way-in"} (tr "workspace.options.interaction-in")]] - [:div.input-radio - [:input {:type "radio" - :id "way-out" - :checked (= :out way) - :name "animation-way" - :value ":out" - :on-change change-way}] - [:label {:for "way-out"} (tr "workspace.options.interaction-out")]]]) - - ;; Direction - (when (ctsi/has-direction? interaction) - [:div.interactions-element.interactions-direction-buttons - [:div.element-set-actions-button - {:class (dom/classnames :active (= direction :right)) - :data-value :right - :on-click change-direction} - i/animate-right] - [:div.element-set-actions-button - {:class (dom/classnames :active (= direction :down)) - :data-value :up - :on-click change-direction} - i/animate-down] - [:div.element-set-actions-button - {:class (dom/classnames :active (= direction :left)) - :data-value :left - :on-click change-direction} - i/animate-left] - [:div.element-set-actions-button - {:class (dom/classnames :active (= direction :up)) - :data-value :down - :on-click change-direction} - i/animate-up]]) - - ;; Duration - (when (ctsi/has-duration? interaction) - [:div.interactions-element - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-duration")] - [:div.input-element {:title (tr "workspace.options.interaction-ms")} - [:> numeric-input* {:ref ext-duration-ref - :on-change change-duration - :value (-> interaction :animation :duration) - :title (tr "workspace.options.interaction-ms")}] - [:span.after (tr "workspace.options.interaction-ms")]]]) - - ;; Easing - (when (ctsi/has-easing? interaction) - [:div.interactions-element - [:span.element-set-subtitle.wide (tr "workspace.options.interaction-easing")] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (str (-> interaction :animation :easing)) - :on-change change-easing} - (for [[value name] (easing-names)] - [:option {:value (str value)} name])] - [:div.interactions-easing-icon - (case (-> interaction :animation :easing) - :linear i/easing-linear - :ease i/easing-ease - :ease-in i/easing-ease-in - :ease-out i/easing-ease-out - :ease-in-out i/easing-ease-in-out)]]) - - ;; Offset effect - (when (ctsi/has-offset-effect? interaction) - [:div.interactions-element - [:div.input-checkbox - [:input {:type "checkbox" - :id (str "offset-effect-" index) - :checked (-> interaction :animation :offset-effect) - :on-change change-offset-effect}] - [:label {:for (str "offset-effect-" index)} - (tr "workspace.options.interaction-offset-effect")]]])])])]))) + ;; Offset effect + (when (ctsi/has-offset-effect? interaction) + [:div {:class (stl/css :property-row)} + [:div {:class (stl/css :checkbox-option)} + [:label {:for (str "offset-effect-" index) + :class (stl/css-case :global/checked (-> interaction :animation :offset-effect))} + [:span {:class (stl/css-case :global/checked (-> interaction :animation :offset-effect))} + (when (-> interaction :animation :offset-effect) + i/status-tick-refactor)] + (tr "workspace.options.interaction-offset-effect") + [:input {:type "checkbox" + :id (str "offset-effect-" index) + :checked (-> interaction :animation :offset-effect) + :on-change change-offset-effect}]]]])])])])) (mf/defc interactions-menu [{:keys [shape] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - interactions (get shape :interactions []) + (let [interactions (get shape :interactions []) options (mf/deref refs/workspace-page-options) flows (:flows options) @@ -1076,76 +704,43 @@ update-interaction (fn [index update-fn] (st/emit! (dwi/update-interaction shape index update-fn)))] - (if new-css-system - [:div {:class (stl/css :interactions-content)} - (if shape - [:& shape-flows {:flows flows - :shape shape}] - [:& page-flows {:flows flows}]) - [:div {:class (stl/css :interaction-options)} - (when (and shape (not (cfh/unframed-shape? shape))) - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? false - :title (tr "workspace.options.interactions") - :class (stl/css :title-spacing-layout-interactions)} + [:div {:class (stl/css :interactions-content)} + (if shape + [:& shape-flows {:flows flows + :shape shape}] + [:& page-flows {:flows flows}]) + [:div {:class (stl/css :interaction-options)} + (when (and shape (not (cfh/unframed-shape? shape))) + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? false + :title (tr "workspace.options.interactions") + :class (stl/css :title-spacing-layout-interactions)} - [:button {:class (stl/css :add-interaction-btn) - :on-click add-interaction} - i/add-refactor]]]) - [:div {:class (stl/css :help-content)} - (when (= (count interactions) 0) - [:* - (when (and shape (not (cfh/unframed-shape? shape))) - [:div {:class (stl/css :help-group)} - [:div {:class (stl/css :interactions-help-icon)} i/add-refactor] - [:div {:class (stl/css :interactions-help)} - (tr "workspace.options.add-interaction")]]) + [:button {:class (stl/css :add-interaction-btn) + :on-click add-interaction} + i/add-refactor]]]) + [:div {:class (stl/css :help-content)} + (when (= (count interactions) 0) + [:* + (when (and shape (not (cfh/unframed-shape? shape))) [:div {:class (stl/css :help-group)} - [:div {:class (stl/css :interactions-help-icon)} i/interaction-refactor] + [:div {:class (stl/css :interactions-help-icon)} i/add-refactor] [:div {:class (stl/css :interactions-help)} - (tr "workspace.options.select-a-shape")]] - [:div {:class (stl/css :help-group)} - [:div {:class (stl/css :interactions-help-icon)} i/play-refactor] - [:div {:class (stl/css :interactions-help)} - (tr "workspace.options.use-play-button")]]])] - [:div {:class (stl/css :groups)} - (for [[index interaction] (d/enumerate interactions)] - [:& interaction-entry {:key (dm/str (:id shape) "-" index) - :index index - :shape shape - :interaction interaction - :update-interaction update-interaction - :remove-interaction remove-interaction}])]]] - - [:* - (if shape - [:& shape-flows {:flows flows - :shape shape}] - [:& page-flows {:flows flows}]) - - [:div.element-set.interactions-options - (when (and shape (not (cfh/unframed-shape? shape))) - [:div.element-set-title - [:span (tr "workspace.options.interactions")] - [:div.add-page {:on-click add-interaction} - i/plus]]) - [:div.element-set-content - (when (= (count interactions) 0) - [:* - (when (and shape (not (cfh/unframed-shape? shape))) - [:* - [:div.interactions-help-icon i/plus] - [:div.interactions-help.separator (tr "workspace.options.add-interaction")]]) - [:div.interactions-help-icon i/interaction] - [:div.interactions-help (tr "workspace.options.select-a-shape")] - [:div.interactions-help-icon i/play] - [:div.interactions-help (tr "workspace.options.use-play-button")]])] - [:div.groups - (for [[index interaction] (d/enumerate interactions)] - [:& interaction-entry {:key (dm/str (:id shape) "-" index) - :index index - :shape shape - :interaction interaction - :update-interaction update-interaction - :remove-interaction remove-interaction}])]]]))) + (tr "workspace.options.add-interaction")]]) + [:div {:class (stl/css :help-group)} + [:div {:class (stl/css :interactions-help-icon)} i/interaction-refactor] + [:div {:class (stl/css :interactions-help)} + (tr "workspace.options.select-a-shape")]] + [:div {:class (stl/css :help-group)} + [:div {:class (stl/css :interactions-help-icon)} i/play-refactor] + [:div {:class (stl/css :interactions-help)} + (tr "workspace.options.use-play-button")]]])] + [:div {:class (stl/css :groups)} + (for [[index interaction] (d/enumerate interactions)] + [:& interaction-entry {:key (dm/str (:id shape) "-" index) + :index index + :shape shape + :interaction interaction + :update-interaction update-interaction + :remove-interaction remove-interaction}])]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs index 7dedfd571d..bdfec509f4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs @@ -14,7 +14,6 @@ [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.select :refer [select]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -33,9 +32,7 @@ (mf/defc layer-menu {::mf/wrap-props false} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - ids (unchecked-get props "ids") - type (unchecked-get props "type") + (let [ids (unchecked-get props "ids") values (unchecked-get props "values") hidden? (:hidden values) @@ -148,90 +145,46 @@ preview-complete?)) (swap! state* assoc :selected-blend-mode current-blend-mode))) - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css-case :element-set-content true - :hidden hidden?)} - [:div {:class (stl/css :select)} - [:& select - {:default-value selected-blend-mode - :options options - :on-change handle-change-blend-mode - :is-open? option-highlighted? - :class (stl/css-case :hidden-select hidden?) - :on-pointer-enter-option handle-blend-mode-enter - :on-pointer-leave-option handle-blend-mode-leave}]] - [:div {:class (stl/css :input) - :title (tr "workspace.options.opacity")} - [:span {:class (stl/css :icon)} "%"] - [:> numeric-input* - {:value (opacity->string current-opacity) - :placeholder (tr "settings.multiple") - :on-change handle-opacity-change - :min 0 - :max 100 - :className (stl/css :numeric-input)}]] + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css-case :element-set-content true + :hidden hidden?)} + [:div {:class (stl/css :select)} + [:& select + {:default-value selected-blend-mode + :options options + :on-change handle-change-blend-mode + :is-open? option-highlighted? + :class (stl/css-case :hidden-select hidden?) + :on-pointer-enter-option handle-blend-mode-enter + :on-pointer-leave-option handle-blend-mode-leave}]] + [:div {:class (stl/css :input) + :title (tr "workspace.options.opacity")} + [:span {:class (stl/css :icon)} "%"] + [:> numeric-input* + {:value (opacity->string current-opacity) + :placeholder (tr "settings.multiple") + :on-change handle-opacity-change + :min 0 + :max 100 + :className (stl/css :numeric-input)}]] - [:div {:class (stl/css :actions)} - (cond - (or (= :multiple hidden?) (not hidden?)) - [:button {:on-click handle-set-hidden - :class (stl/css :hidden-btn)} i/shown-refactor] + [:div {:class (stl/css :actions)} + (cond + (or (= :multiple hidden?) (not hidden?)) + [:button {:on-click handle-set-hidden + :class (stl/css :hidden-btn)} i/shown-refactor] - :else - [:button {:on-click handle-set-visible - :class (stl/css :hidden-btn)} i/hide-refactor]) + :else + [:button {:on-click handle-set-visible + :class (stl/css :hidden-btn)} i/hide-refactor]) - (cond - (or (= :multiple blocked?) (not blocked?)) - [:button {:on-click handle-set-blocked - :class (stl/css :lock-btn)} i/unlock-refactor] + (cond + (or (= :multiple blocked?) (not blocked?)) + [:button {:on-click handle-set-blocked + :class (stl/css :lock-btn)} i/unlock-refactor] - :else - [:button {:on-click handle-set-unblocked - :class (stl/css-case :lock-btn true - :locked blocked?)} i/lock-refactor])]]] - - [:div.element-set - [:div.element-set-title - [:span - (case type - :multiple (tr "workspace.options.layer-options.title.multiple") - :group (tr "workspace.options.layer-options.title.group") - (tr "workspace.options.layer-options.title"))]] - - [:div.element-set-content - [:div.row-flex - [:& select - {:class "flex-grow no-check" - :default-value selected-blend-mode - :options options - :on-change handle-change-blend-mode - :is-open? option-highlighted? - :on-pointer-enter-option handle-blend-mode-enter - :on-pointer-leave-option handle-blend-mode-leave}] - - [:div.input-element {:title (tr "workspace.options.opacity") - :class "percentail"} - [:> numeric-input* - {:value (opacity->string current-opacity) - :placeholder (tr "settings.multiple") - :on-change handle-opacity-change - :min 0 - :max 100}]] - - [:div.element-set-actions.layer-actions - (cond - (or (= :multiple hidden?) (not hidden?)) - [:div.element-set-actions-button {:on-click handle-set-hidden} i/eye] - - :else - [:div.element-set-actions-button {:on-click handle-set-visible} i/eye-closed]) - - (cond - (or (= :multiple blocked?) (not blocked?)) - [:div.element-set-actions-button {:on-click handle-set-blocked} i/unlock] - - :else - [:div.element-set-actions-button {:on-click handle-set-unblocked} i/lock])]]]]))) + :else + [:button {:on-click handle-set-unblocked + :class (stl/css-case :lock-btn true + :locked blocked?)} i/lock-refactor])]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss index 7d8f31d768..93be5aa25c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss @@ -8,48 +8,48 @@ .element-set { margin-bottom: $s-8; - .element-set-content { +} +.element-set-content { + display: flex; + height: $s-32; + gap: $s-4; + .select { + width: $s-124; + padding: 0; + } + .input { + @extend .input-element; + width: $s-60; + } + .actions { display: flex; - height: $s-32; gap: $s-4; - .select { - width: $s-124; - padding: 0; + .hidden-btn, + .lock-btn { + @extend .button-tertiary; + border-radius: $br-8; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + } + } + + &.hidden { + .hidden-select { + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); } .input { - @extend .input-element; - width: $s-60; - } - .actions { - display: flex; - gap: $s-4; - .hidden-btn, - .lock-btn { - @extend .button-tertiary; - border-radius: $br-8; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); + .icon { + stroke: var(--input-foreground-color-disabled); } - } - - &.hidden { - .hidden-select { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - } - .input { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - .icon { - stroke: var(--input-foreground-color-disabled); - } - .numeric-input { - color: var(--input-foreground-color-disabled); - } + .numeric-input { + color: var(--input-foreground-color-disabled); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index dc97af314b..c9069edbbf 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -23,7 +23,6 @@ [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.formats :as fmt] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] @@ -41,29 +40,6 @@ :column i/column-refactor :column-reverse i/column-reverse-refactor)) -(mf/defc direction-btn - [{:keys [dir saved-dir on-click icon?] :as props}] - (let [handle-on-click - (mf/use-fn - (mf/deps on-click dir) - (fn [] - (when (some? on-click) - (on-click dir))))] - - [:button.dir.tooltip.tooltip-bottom - {:class (dom/classnames :active (= saved-dir dir) - :row (= :row dir) - :row-reverse (= :row-reverse dir) - :column-reverse (= :column-reverse dir) - :column (= :column dir)) - :key (dm/str "direction-" dir) - :alt (str/replace (str/capital (d/name dir)) "-" " ") - :on-click handle-on-click} - (if icon? - i/auto-direction - (str/replace (str/capital (d/name dir)) "-" " "))])) - - ;; FLEX COMPONENTS (def layout-container-flex-attrs @@ -85,86 +61,6 @@ :layout-grid-rows]) (defn get-layout-flex-icon - [type val is-col?] - (case type - :align-items - (if is-col? - (case val - :start i/align-items-column-start - :end i/align-items-column-end - :center i/align-items-column-center - :stretch i/align-items-column-strech - :baseline i/align-items-column-baseline) - (case val - :start i/align-items-row-start - :end i/align-items-row-end - :center i/align-items-row-center - :stretch i/align-items-row-strech - :baseline i/align-items-row-baseline)) - - :justify-content - (if is-col? - (case val - :start i/justify-content-column-start - :end i/justify-content-column-end - :center i/justify-content-column-center - :space-around i/justify-content-column-around - :space-evenly i/justify-content-column-evenly - :space-between i/justify-content-column-between) - (case val - :start i/justify-content-row-start - :end i/justify-content-row-end - :center i/justify-content-row-center - :space-around i/justify-content-row-around - :space-evenly i/justify-content-row-evenly - :space-between i/justify-content-row-between)) - - :align-content - (if is-col? - (case val - :start i/align-content-column-start - :end i/align-content-column-end - :center i/align-content-column-center - :space-around i/align-content-column-around - :space-evenly i/align-content-column-evenly - :space-between i/align-content-column-between - :stretch nil) - - (case val - :start i/align-content-row-start - :end i/align-content-row-end - :center i/align-content-row-center - :space-around i/align-content-row-around - :space-evenly i/align-content-row-evenly - :space-between i/align-content-row-between - :stretch nil)) - - (case val - :start i/align-content-row-start - :end i/align-content-row-end - :center i/align-content-row-center - :space-around i/align-content-row-around - :space-between i/align-content-row-between - :stretch nil) - - :align-self - (if is-col? - (case val - :auto i/minus - :start i/align-self-row-left - :end i/align-self-row-right - :center i/align-self-row-center - :stretch i/align-self-row-strech - :baseline i/align-self-row-baseline) - (case val - :auto i/minus - :start i/align-self-column-top - :end i/align-self-column-bottom - :center i/align-self-column-center - :stretch i/align-self-column-strech - :baseline i/align-self-column-baseline)))) - -(defn get-layout-flex-icon-refactor [type val is-col?] (case type :align-items @@ -276,249 +172,118 @@ (mf/defc direction-row-flex [{:keys [saved-dir on-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& radio-buttons {:selected (d/name saved-dir) - :on-change on-change - :name "flex-direction"} - [:& radio-button {:value "row" - :id "flex-direction-row" - :title "Row" - :icon (dir-icons-refactor :row)}] - [:& radio-button {:value "row-reverse" - :id "flex-direction-row-reverse" - :title "Row reverse" - :icon (dir-icons-refactor :row-reverse)}] - [:& radio-button {:value "column" - :id "flex-direction-column" - :title "Column" - :icon (dir-icons-refactor :column)}] - [:& radio-button {:value "column-reverse" - :id "flex-direction-column-reverse" - :title "Column reverse" - :icon (dir-icons-refactor :column-reverse)}]] - [:* - (for [dir [:row :row-reverse :column :column-reverse]] - [:& direction-btn {:key (d/name dir) - :dir dir - :saved-dir saved-dir - :on-click on-change - :icon? true}])]))) + [:& radio-buttons {:selected (d/name saved-dir) + :on-change on-change + :name "flex-direction"} + [:& radio-button {:value "row" + :id "flex-direction-row" + :title "Row" + :icon (dir-icons-refactor :row)}] + [:& radio-button {:value "row-reverse" + :id "flex-direction-row-reverse" + :title "Row reverse" + :icon (dir-icons-refactor :row-reverse)}] + [:& radio-button {:value "column" + :id "flex-direction-column" + :title "Column" + :icon (dir-icons-refactor :column)}] + [:& radio-button {:value "column-reverse" + :id "flex-direction-column-reverse" + :title "Column reverse" + :icon (dir-icons-refactor :column-reverse)}]]) (mf/defc wrap-row [{:keys [wrap-type on-click] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:button {:class (stl/css-case :wrap-button true - :selected (= wrap-type :wrap)) - :title (if (= :wrap wrap-type) - "No wrap" - "Wrap") - :on-click on-click} - i/wrap-refactor] - - [:* - [:button.tooltip.tooltip-bottom - {:class (dom/classnames :active (= wrap-type :nowrap)) - :alt "No wrap" - :data-value :nowrap - :on-click on-click - :style {:padding 0}} - [:span.no-wrap i/minus]] - [:button.wrap.tooltip.tooltip-bottom - {:class (dom/classnames :active (= wrap-type :wrap)) - :alt "Wrap" - :data-value :wrap - :on-click on-click} - i/auto-wrap]]))) + [:button {:class (stl/css-case :wrap-button true + :selected (= wrap-type :wrap)) + :title (if (= :wrap wrap-type) + "No wrap" + "Wrap") + :on-click on-click} + i/wrap-refactor]) (mf/defc align-row [{:keys [is-col? align-items on-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& radio-buttons {:selected (d/name align-items) - :on-change on-change - :name "flex-align-items"} - [:& radio-button {:value "start" - :icon (get-layout-flex-icon-refactor :align-items :start is-col?) - :title "Align items start" - :id "align-items-start"}] - [:& radio-button {:value "center" - :icon (get-layout-flex-icon-refactor :align-items :center is-col?) - :title "Align items center" - :id "align-items-center"}] - [:& radio-button {:value "end" - :icon (get-layout-flex-icon-refactor :align-items :end is-col?) - :title "Align items end" - :id "align-items-end"}]] - - [:div.align-items-style - [:button.align-start.tooltip.tooltip-bottom - {:class (dom/classnames :active (= align-items :start)) - :alt "Align items start" - :data-value :start - :on-click on-change} - (get-layout-flex-icon :align-items :start is-col?)] - [:button.align-start.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= align-items :center)) - :alt "Align items center" - :data-value :center - :on-click on-change} - (get-layout-flex-icon :align-items :center is-col?)] - [:button.align-start.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= align-items :end)) - :alt "Align items end" - :data-value :end - :on-click on-change} - (get-layout-flex-icon :align-items :end is-col?)]]))) + [:& radio-buttons {:selected (d/name align-items) + :on-change on-change + :name "flex-align-items"} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :align-items :start is-col?) + :title "Align items start" + :id "align-items-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :align-items :center is-col?) + :title "Align items center" + :id "align-items-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :align-items :end is-col?) + :title "Align items end" + :id "align-items-end"}]]) (mf/defc align-content-row [{:keys [is-col? align-content on-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& radio-buttons {:selected (d/name align-content) - :on-change on-change - :name "flex-align-content"} - [:& radio-button {:value "start" - :icon (get-layout-flex-icon-refactor :align-content :start is-col?) - :title "Align content start" - :id "align-content-start"}] - [:& radio-button {:value "center" - :icon (get-layout-flex-icon-refactor :align-content :center is-col?) - :title "Align content center" - :id "align-content-center"}] - [:& radio-button {:value "end" - :icon (get-layout-flex-icon-refactor :align-content :end is-col?) - :title "Align content end" - :id "align-content-end"}] - [:& radio-button {:value "space-between" - :icon (get-layout-flex-icon-refactor :align-content :space-between is-col?) - :title "Align content space-between" - :id "align-content-space-between"}] - [:& radio-button {:value "space-around" - :icon (get-layout-flex-icon-refactor :align-content :space-around is-col?) - :title "Align content space-around" - :id "align-content-space-around"}] - [:& radio-button {:value "space-evenly" - :icon (get-layout-flex-icon-refactor :align-content :space-evenly is-col?) - :title "Align content space-evenly" - :id "align-content-space-evenly"}]] - [:* - [:div.align-content-style - [:button.align-content.tooltip.tooltip-bottom - {:class (dom/classnames :active (= align-content :start)) - :alt "Align content start" - :data-value :start - :on-click on-change} - (get-layout-flex-icon :align-content :start is-col?)] - [:button.align-content.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= align-content :center)) - :alt "Align content center" - :data-value :center - :on-click on-change} - (get-layout-flex-icon :align-content :center is-col?)] - [:button.align-content.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= align-content :end)) - :alt "Align content end" - :data-value :end - :on-click on-change} - (get-layout-flex-icon :align-content :end is-col?)]] - [:div.align-content-style - [:button.align-content.tooltip.tooltip-bottom - {:class (dom/classnames :active (= align-content :space-between)) - :alt "Align content space-between" - :data-value :space-between - :on-click on-change} - (get-layout-flex-icon :align-content :space-between is-col?)] - [:button.align-content.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= align-content :space-around)) - :alt "Align content space-around" - :data-value :space-around - :on-click on-change} - (get-layout-flex-icon :align-content :space-around is-col?)] - [:button.align-content.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= align-content :space-evenly)) - :alt "Align content space-evenly" - :data-value :space-evenly - :on-click on-change} - (get-layout-flex-icon :align-content :space-evenly is-col?)]]]))) + [:& radio-buttons {:selected (d/name align-content) + :on-change on-change + :name "flex-align-content"} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :align-content :start is-col?) + :title "Align content start" + :id "align-content-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :align-content :center is-col?) + :title "Align content center" + :id "align-content-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :align-content :end is-col?) + :title "Align content end" + :id "align-content-end"}] + [:& radio-button {:value "space-between" + :icon (get-layout-flex-icon :align-content :space-between is-col?) + :title "Align content space-between" + :id "align-content-space-between"}] + [:& radio-button {:value "space-around" + :icon (get-layout-flex-icon :align-content :space-around is-col?) + :title "Align content space-around" + :id "align-content-space-around"}] + [:& radio-button {:value "space-evenly" + :icon (get-layout-flex-icon :align-content :space-evenly is-col?) + :title "Align content space-evenly" + :id "align-content-space-evenly"}]]) (mf/defc justify-content-row [{:keys [is-col? justify-content on-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& radio-buttons {:selected (d/name justify-content) - :on-change on-change - :name "flex-justify"} - [:& radio-button {:value "start" - :icon (get-layout-flex-icon-refactor :justify-content :start is-col?) - :title "Justify content start" - :id "justify-content-start"}] - [:& radio-button {:value "center" - :icon (get-layout-flex-icon-refactor :justify-content :center is-col?) - :title "Justify content center" - :id "justify-content-center"}] - [:& radio-button {:value "end" - :icon (get-layout-flex-icon-refactor :justify-content :end is-col?) - :title "Justify content end" - :id "justify-content-end"}] - [:& radio-button {:value "space-between" - :icon (get-layout-flex-icon-refactor :justify-content :space-between is-col?) - :title "Justify content space-between" - :id "justify-content-space-between"}] - [:& radio-button {:value "space-around" - :icon (get-layout-flex-icon-refactor :justify-content :space-around is-col?) - :title "Justify content space-around" - :id "justify-content-space-around"}] - [:& radio-button {:value "space-evenly" - :icon (get-layout-flex-icon-refactor :justify-content :space-evenly is-col?) - :title "Justify content space-evenly" - :id "justify-content-space-evenly"}]] - [:* - [:div.justify-content-style - [:button.justify.tooltip.tooltip-bottom - {:class (dom/classnames :active (= justify-content :start)) - :alt "Justify content start" - :data-value :start - :on-click on-change} - (get-layout-flex-icon :justify-content :start is-col?)] - [:button.justify.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= justify-content :center)) - :data-value :center - :alt "Justify content center" - :on-click on-change} - (get-layout-flex-icon :justify-content :center is-col?)] - [:button.justify.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= justify-content :end)) - :alt "Justify content end" - :data-value :end - :on-click on-change} - (get-layout-flex-icon :justify-content :end is-col?)]] - [:div.justify-content-style - [:button.justify.tooltip.tooltip-bottom - {:class (dom/classnames :active (= justify-content :space-between)) - :alt "Justify content space-between" - :data-value :space-between - :on-click on-change} - (get-layout-flex-icon :justify-content :space-between is-col?)] - [:button.justify.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= justify-content :space-around)) - :alt "Justify content space-around" - :data-value :space-around - :on-click on-change} - (get-layout-flex-icon :justify-content :space-around is-col?)] - [:button.justify.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= justify-content :space-evenly)) - :alt "Justify content space-evenly" - :data-value :space-evenly - :on-click on-change} - (get-layout-flex-icon :justify-content :space-evenly is-col?)]]]))) + [:& radio-buttons {:selected (d/name justify-content) + :on-change on-change + :name "flex-justify"} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :justify-content :start is-col?) + :title "Justify content start" + :id "justify-content-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :justify-content :center is-col?) + :title "Justify content center" + :id "justify-content-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :justify-content :end is-col?) + :title "Justify content end" + :id "justify-content-end"}] + [:& radio-button {:value "space-between" + :icon (get-layout-flex-icon :justify-content :space-between is-col?) + :title "Justify content space-between" + :id "justify-content-space-between"}] + [:& radio-button {:value "space-around" + :icon (get-layout-flex-icon :justify-content :space-around is-col?) + :title "Justify content space-around" + :id "justify-content-space-around"}] + [:& radio-button {:value "space-evenly" + :icon (get-layout-flex-icon :justify-content :space-evenly is-col?) + :title "Justify content space-evenly" + :id "justify-content-space-evenly"}]]) (mf/defc padding-section [{:keys [values on-change-style on-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - padding-type (:layout-padding-type values) + (let [padding-type (:layout-padding-type values) toggle-padding-mode (mf/use-fn @@ -551,171 +316,110 @@ ;;on destroy component (select-paddings false false false false)))) - (if new-css-system - [:div {:class (stl/css :padding-group)} - [:div {:class (stl/css :padding-inputs)} - (cond - (= padding-type :simple) - [:div {:class (stl/css :paddings-simple)} - [:div {:class (stl/css :padding-simple) - :title "Vertical padding"} - [:span {:class (stl/css :icon)} - i/padding-top-bottom-refactor] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :on-change (partial on-change :simple :p1) - :on-focus #(do - (dom/select-target %) - (select-paddings true false true false)) - :nillable true - :min 0 - :value p1}]] - [:div {:class (stl/css :padding-simple) - :title "Horizontal padding"} + [:div {:class (stl/css :padding-group)} + [:div {:class (stl/css :padding-inputs)} + (cond + (= padding-type :simple) + [:div {:class (stl/css :paddings-simple)} + [:div {:class (stl/css :padding-simple) + :title "Vertical padding"} + [:span {:class (stl/css :icon)} + i/padding-top-bottom-refactor] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :on-change (partial on-change :simple :p1) + :on-focus #(do + (dom/select-target %) + (select-paddings true false true false)) + :nillable true + :min 0 + :value p1}]] + [:div {:class (stl/css :padding-simple) + :title "Horizontal padding"} - [:span {:class (stl/css :icon)} - i/padding-left-right-refactor] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :on-change (partial on-change :simple :p2) - :on-focus #(do (dom/select-target %) - (select-paddings false true false true)) - :on-blur #(select-paddings false false false false) - :nillable true - :min 0 - :value p2}]]] - (= padding-type :multiple) - [:div {:class (stl/css :paddings-multiple)} + [:span {:class (stl/css :icon)} + i/padding-left-right-refactor] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :on-change (partial on-change :simple :p2) + :on-focus #(do (dom/select-target %) + (select-paddings false true false true)) + :on-blur #(select-paddings false false false false) + :nillable true + :min 0 + :value p2}]]] + (= padding-type :multiple) + [:div {:class (stl/css :paddings-multiple)} - [:div {:class (stl/css :padding-multiple) - :title "Top padding"} - [:span {:class (stl/css :icon)} - i/padding-top-refactor] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :on-change (partial on-change :multiple :p1) - :on-focus #(do (dom/select-target %) - (select-padding :p1)) - :on-blur #(select-paddings false false false false) - :nillable true - :min 0 - :value (:p1 (:layout-padding values))}]] + [:div {:class (stl/css :padding-multiple) + :title "Top padding"} + [:span {:class (stl/css :icon)} + i/padding-top-refactor] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :on-change (partial on-change :multiple :p1) + :on-focus #(do (dom/select-target %) + (select-padding :p1)) + :on-blur #(select-paddings false false false false) + :nillable true + :min 0 + :value (:p1 (:layout-padding values))}]] - [:div {:class (stl/css :padding-multiple) - :title "Right padding"} - [:span {:class (stl/css :icon)} - i/padding-right-refactor] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :on-change (partial on-change :multiple :p2) - :on-focus #(do (dom/select-target %) - (select-padding :p2)) - :on-blur #(select-paddings false false false false) - :nillable true - :min 0 - :value (:p2 (:layout-padding values))}]] + [:div {:class (stl/css :padding-multiple) + :title "Right padding"} + [:span {:class (stl/css :icon)} + i/padding-right-refactor] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :on-change (partial on-change :multiple :p2) + :on-focus #(do (dom/select-target %) + (select-padding :p2)) + :on-blur #(select-paddings false false false false) + :nillable true + :min 0 + :value (:p2 (:layout-padding values))}]] - [:div {:class (stl/css :padding-multiple) - :title "Bottom padding"} - [:span {:class (stl/css :icon)} - i/padding-bottom-refactor] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :on-change (partial on-change :multiple :p3) - :on-focus #(do (dom/select-target %) - (select-padding :p3)) - :on-blur #(select-paddings false false false false) - :nillable true - :min 0 - :value (:p3 (:layout-padding values))}]] + [:div {:class (stl/css :padding-multiple) + :title "Bottom padding"} + [:span {:class (stl/css :icon)} + i/padding-bottom-refactor] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :on-change (partial on-change :multiple :p3) + :on-focus #(do (dom/select-target %) + (select-padding :p3)) + :on-blur #(select-paddings false false false false) + :nillable true + :min 0 + :value (:p3 (:layout-padding values))}]] - [:div {:class (stl/css :padding-multiple) - :title "Left padding"} - [:span {:class (stl/css :icon)} - i/padding-left-refactor] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :on-change (partial on-change :multiple :p4) - :on-focus #(do (dom/select-target %) - (select-padding :p4)) - :on-blur #(select-paddings false false false false) - :nillable true - :min 0 - :value (:p4 (:layout-padding values))}]]])] - [:button {:class (stl/css-case :padding-toggle true - :selected (= padding-type :multiple)) - :on-click toggle-padding-mode} - i/padding-extended-refactor]] - - [:div.padding-row - (cond - (= padding-type :simple) - - [:div.padding-group - [:div.padding-item.tooltip.tooltip-bottom-left - {:alt "Vertical padding"} - [:span.icon.rotated i/auto-padding-both-sides] - [:> numeric-input* - {:placeholder "--" - :on-change (partial on-change :simple :p1) - :on-focus #(do - (dom/select-target %) - (select-paddings true false true false)) - :nillable true - :min 0 - :value p1}]] - - [:div.padding-item.tooltip.tooltip-bottom-left - {:alt "Horizontal padding"} - [:span.icon i/auto-padding-both-sides] - [:> numeric-input* - {:placeholder "--" - :on-change (partial on-change :simple :p2) - :on-focus #(do (dom/select-target %) - (select-paddings false true false true)) - :on-blur #(select-paddings false false false false) - :nillable true - :min 0 - :value p2}]]] - - (= padding-type :multiple) - [:div.wrapper - (for [num [:p1 :p2 :p3 :p4]] - [:div.tooltip.tooltip-bottom - {:key (dm/str "padding-" (d/name num)) - :alt (case num - :p1 "Top" - :p2 "Right" - :p3 "Bottom" - :p4 "Left")} - [:div.input-element.auto - [:> numeric-input* - {:placeholder "--" - :on-change (partial on-change :multiple num) - :on-focus #(do (dom/select-target %) - (select-padding num)) - :on-blur #(select-paddings false false false false) - :nillable true - :min 0 - :value (num (:layout-padding values))}]]])]) - - [:div.padding-icons - [:div.padding-icon.tooltip.tooltip-bottom-left - {:class (dom/classnames :selected (= padding-type :multiple)) - :alt "Independent paddings" - :on-click toggle-padding-mode} - i/auto-padding-side]]]))) + [:div {:class (stl/css :padding-multiple) + :title "Left padding"} + [:span {:class (stl/css :icon)} + i/padding-left-refactor] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :on-change (partial on-change :multiple :p4) + :on-focus #(do (dom/select-target %) + (select-padding :p4)) + :on-blur #(select-paddings false false false false) + :nillable true + :min 0 + :value (:p4 (:layout-padding values))}]]])] + [:button {:class (stl/css-case :padding-toggle true + :selected (= padding-type :multiple)) + :on-click toggle-padding-mode} + i/padding-extended-refactor]])) (mf/defc gap-section [{:keys [is-col? wrap-type gap-selected? on-change gap-value]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - select-gap + (let [select-gap (fn [gap] (st/emit! (udw/set-gap-selected gap)))] @@ -725,89 +429,47 @@ ;;on destroy component (select-gap nil)))) - (if new-css-system - [:div {:class (stl/css :gap-group)} - [:div {:class (stl/css-case :row-gap true - :disabled (and (= :nowrap wrap-type) (not is-col?))) - :title "Row gap"} - [:span {:class (stl/css :icon)} i/gap-vertical-refactor] - [:> numeric-input* {:className (stl/css :numeric-input true) - :no-validate true - :placeholder "--" - :on-focus (fn [event] - (select-gap :row-gap) - (reset! gap-selected? :row-gap) - (dom/select-target event)) - :on-change (partial on-change (= :nowrap wrap-type) :row-gap) - :on-blur (fn [_] - (select-gap nil) - (reset! gap-selected? :none)) - :nillable true - :min 0 - :value (:row-gap gap-value) - :disabled (and (= :nowrap wrap-type) (not is-col?))}]] + [:div {:class (stl/css :gap-group)} + [:div {:class (stl/css-case :row-gap true + :disabled (and (= :nowrap wrap-type) (not is-col?))) + :title "Row gap"} + [:span {:class (stl/css :icon)} i/gap-vertical-refactor] + [:> numeric-input* {:className (stl/css :numeric-input true) + :no-validate true + :placeholder "--" + :on-focus (fn [event] + (select-gap :row-gap) + (reset! gap-selected? :row-gap) + (dom/select-target event)) + :on-change (partial on-change (= :nowrap wrap-type) :row-gap) + :on-blur (fn [_] + (select-gap nil) + (reset! gap-selected? :none)) + :nillable true + :min 0 + :value (:row-gap gap-value) + :disabled (and (= :nowrap wrap-type) (not is-col?))}]] - [:div {:class (stl/css-case :column-gap true - :disabled (and (= :nowrap wrap-type) is-col?)) - :title "Column gap"} - [:span {:class (stl/css :icon)} - i/gap-horizontal-refactor] - [:> numeric-input* {:className (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-focus (fn [event] - (select-gap :column-gap) - (reset! gap-selected? :column-gap) - (dom/select-target event)) - :on-change (partial on-change (= :nowrap wrap-type) :column-gap) - :on-blur (fn [_] - (select-gap nil) - (reset! gap-selected? :none)) - :nillable true - :min 0 - :value (:column-gap gap-value) - :disabled (and (= :nowrap wrap-type) is-col?)}]]] - - [:div.layout-row - [:div.gap.row-title "Gap"] - [:div.gap-group - [:div.gap-row.tooltip.tooltip-bottom-left - {:alt "Column gap"} - [:span.icon - i/auto-gap] - [:> numeric-input* {:no-validate true - :placeholder "--" - :on-focus (fn [event] - (select-gap :column-gap) - (reset! gap-selected? :column-gap) - (dom/select-target event)) - :on-change (partial on-change (= :nowrap wrap-type) :column-gap) - :on-blur (fn [_] - (select-gap nil) - (reset! gap-selected? :none)) - :nillable true - :min 0 - :value (:column-gap gap-value) - :disabled (and (= :nowrap wrap-type) is-col?)}]] - - [:div.gap-row.tooltip.tooltip-bottom-left - {:alt "Row gap"} - [:span.icon.rotated - i/auto-gap] - [:> numeric-input* {:no-validate true - :placeholder "--" - :on-focus (fn [event] - (select-gap :row-gap) - (reset! gap-selected? :row-gap) - (dom/select-target event)) - :on-change (partial on-change (= :nowrap wrap-type) :row-gap) - :on-blur (fn [_] - (select-gap nil) - (reset! gap-selected? :none)) - :nillable true - :min 0 - :value (:row-gap gap-value) - :disabled (and (= :nowrap wrap-type) (not is-col?))}]]]]))) + [:div {:class (stl/css-case :column-gap true + :disabled (and (= :nowrap wrap-type) is-col?)) + :title "Column gap"} + [:span {:class (stl/css :icon)} + i/gap-horizontal-refactor] + [:> numeric-input* {:className (stl/css :numeric-input) + :no-validate true + :placeholder "--" + :on-focus (fn [event] + (select-gap :column-gap) + (reset! gap-selected? :column-gap) + (dom/select-target event)) + :on-change (partial on-change (= :nowrap wrap-type) :column-gap) + :on-blur (fn [_] + (select-gap nil) + (reset! gap-selected? :none)) + :nillable true + :min 0 + :value (:column-gap gap-value) + :disabled (and (= :nowrap wrap-type) is-col?)}]]])) ;; GRID COMPONENTS @@ -835,36 +497,22 @@ :space-evenly i/grid-justify-content-row-between)))) (mf/defc direction-row-grid - [{:keys [saved-dir on-change on-click] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& radio-buttons {:selected (d/name saved-dir) - :on-change on-change - :name "grid-direction"} - [:& radio-button {:value "row" - :id "grid-direction-row" - :title "Row" - :icon (dir-icons-refactor :row)}] - [:& radio-button {:value "column" - :id "grid-direction-column" - :title "Column" - :icon (dir-icons-refactor :column)}]] - [:* - [:& direction-btn {:key "grid-direction-row" - :dir :row - :saved-dir saved-dir - :on-click on-click - :icon? true}] - [:& direction-btn {:key "grid-direction-column" - :dir :column - :saved-dir saved-dir - :on-click on-click - :icon? true}]]))) + [{:keys [saved-dir on-change] :as props}] + [:& radio-buttons {:selected (d/name saved-dir) + :on-change on-change + :name "grid-direction"} + [:& radio-button {:value "row" + :id "grid-direction-row" + :title "Row" + :icon (dir-icons-refactor :row)}] + [:& radio-button {:value "column" + :id "grid-direction-column" + :title "Column" + :icon (dir-icons-refactor :column)}]]) (mf/defc grid-edit-mode [{:keys [id] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - edition (mf/deref refs/selected-edition) + (let [edition (mf/deref refs/selected-edition) active? (= id edition) toggle-edit-mode @@ -874,81 +522,43 @@ (if-not active? (st/emit! (udw/start-edition-mode id)) (st/emit! :interrupt))))] - (if new-css-system - [:button - {:class (stl/css :edit-mode-btn) - :alt "Grid edit mode" - :on-click toggle-edit-mode} - (tr "workspace.layout_grid.editor.options.edit-grid")] - - [:button.tooltip.tooltip-bottom-left - {:class (dom/classnames :active active?) - :alt "Grid edit mode" - :on-click toggle-edit-mode - :style {:padding 0}} - (tr "workspace.layout_grid.editor.options.edit-grid") - i/grid-layout-mode]))) + [:button + {:class (stl/css :edit-mode-btn) + :alt "Grid edit mode" + :on-click toggle-edit-mode} + (tr "workspace.layout_grid.editor.options.edit-grid")])) (mf/defc align-grid-row [{:keys [is-col? align-items set-align] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - type (if is-col? :column :row)] - (if new-css-system - [:& radio-buttons {:selected (d/name align-items) - :on-change #(set-align % type) - :name (dm/str "flex-align-items-" (d/name type))} - [:& radio-button {:value "start" - :icon (get-layout-grid-icon-refactor :align-items :start is-col?) - :title "Align items start" - :id (dm/str "align-items-start-" (d/name type))}] - [:& radio-button {:value "center" - :icon (get-layout-grid-icon-refactor :align-items :center is-col?) - :title "Align items center" - :id (dm/str "align-items-center-" (d/name type))}] - [:& radio-button {:value "end" - :icon (get-layout-grid-icon-refactor :align-items :end is-col?) - :title "Align items end" - :id (dm/str "align-items-end-" (d/name type))}]] - [:div.align-items-style - (for [align [:start :center :end]] - [:button.align-start.tooltip - {:class (dom/classnames :active (= align-items align) - :tooltip-bottom-left (not= align :start) - :tooltip-bottom (= align :start)) - :alt (if is-col? - (dm/str "justify-items: " (d/name align)) - (dm/str "align-items: " (d/name align))) - :on-click #(set-align align type) - :key (dm/str "align-items" (d/name align))} - (get-layout-flex-icon :align-items align is-col?)])]))) + (let [type (if is-col? :column :row)] + [:& radio-buttons {:selected (d/name align-items) + :on-change #(set-align % type) + :name (dm/str "flex-align-items-" (d/name type))} + [:& radio-button {:value "start" + :icon (get-layout-grid-icon-refactor :align-items :start is-col?) + :title "Align items start" + :id (dm/str "align-items-start-" (d/name type))}] + [:& radio-button {:value "center" + :icon (get-layout-grid-icon-refactor :align-items :center is-col?) + :title "Align items center" + :id (dm/str "align-items-center-" (d/name type))}] + [:& radio-button {:value "end" + :icon (get-layout-grid-icon-refactor :align-items :end is-col?) + :title "Align items end" + :id (dm/str "align-items-end-" (d/name type))}]])) (mf/defc justify-grid-row [{:keys [is-col? justify-items set-justify] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - type (if is-col? :column :row)] + (let [type (if is-col? :column :row)] - (if new-css-system - [:& radio-buttons {:selected (d/name justify-items) - :on-change #(set-justify % type) - :name (dm/str "grid-justify-items-" (d/name type))} - (for [justify [:start :center :end :space-around :space-between :stretch]] - [:& radio-button {:value (d/name justify) - :icon (get-layout-grid-icon-refactor :justify-items justify is-col?) - :title (dm/str "Justify items " (d/name justify)) - :id (dm/str "justify-items-" (d/name justify) "-" (d/name type))}])] - - [:div.justify-content-style - (for [align [:start :center :end :space-around :space-between :stretch]] - [:button.align-start.tooltip - {:class (dom/classnames :active (= justify-items align) - :tooltip-bottom-left (not= align :start) - :tooltip-bottom (= align :start)) - :alt (if is-col? - (dm/str "align-content: " (d/name align)) - (dm/str "justify-content: " (d/name align))) - :on-click #(set-justify align type) - :key (dm/str "justify-content" (d/name align))} - (get-layout-grid-icon :justify-items align is-col?)])]))) + [:& radio-buttons {:selected (d/name justify-items) + :on-change #(set-justify % type) + :name (dm/str "grid-justify-items-" (d/name type))} + (for [justify [:start :center :end :space-around :space-between :stretch]] + [:& radio-button {:value (d/name justify) + :icon (get-layout-grid-icon-refactor :justify-items justify is-col?) + :title (dm/str "Justify items " (d/name justify)) + :id (dm/str "justify-items-" (d/name justify) "-" (d/name type))}])])) (defn manage-values [{:keys [value type]}] (case type @@ -959,10 +569,18 @@ value)) (mf/defc grid-track-info - [{:keys [is-col? type index column set-column-value set-column-type remove-element reorder-track hover-track on-select-track]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) + [{:keys [is-col? + type + index + column + set-column-value + set-column-type + remove-element + reorder-track + hover-track + on-select-track]}] - drop-track + (let [drop-track (mf/use-fn (mf/deps type reorder-track index) (fn [drop-position data event] @@ -996,89 +614,50 @@ :column column} :draggable? true)] - (if new-css-system - [:div {:class - (stl/css-case :track-info true - :dnd-over-top (or (= (:over dprops) :top) - (= (:over dprops) :center)) - :dnd-over-bot (= (:over dprops) :bot)) - :ref dref - :on-pointer-enter pointer-enter - :on-pointer-leave pointer-leave} + [:div {:class (stl/css-case :track-info true + :dnd-over-top (or (= (:over dprops) :top) + (= (:over dprops) :center)) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref + :on-pointer-enter pointer-enter + :on-pointer-leave pointer-leave} - [:div {:class (stl/css :track-info-container)} - [:div {:class (stl/css :track-info-dir-icon) - :on-click handle-select-track} - (if is-col? i/flex-vertical-refactor i/flex-horizontal-refactor)] + [:div {:class (stl/css :track-info-container)} + [:div {:class (stl/css :track-info-dir-icon) + :on-click handle-select-track} + (if is-col? i/flex-vertical-refactor i/flex-horizontal-refactor)] - [:div {:class (stl/css :track-info-value)} - [:> numeric-input* {:no-validate true - :value (:value column) - :on-change #(set-column-value type index %) - :placeholder "--" - :min 0 - :disabled (= :auto (:type column))}]] + [:div {:class (stl/css :track-info-value)} + [:> numeric-input* {:no-validate true + :value (:value column) + :on-change #(set-column-value type index %) + :placeholder "--" + :min 0 + :disabled (= :auto (:type column))}]] - [:div {:class (stl/css :track-info-unit)} - [:& select - {:class (stl/css :track-info-unit-selector) - :default-value (:type column) - :options [{:value :flex :label "FR"} - {:value :auto :label "AUTO"} - {:value :fixed :label "PX"} - {:value :percent :label "%"}] - :on-change #(set-column-type type index %)}]]] + [:div {:class (stl/css :track-info-unit)} + [:& select {:class (stl/css :track-info-unit-selector) + :default-value (:type column) + :options [{:value :flex :label "FR"} + {:value :auto :label "AUTO"} + {:value :fixed :label "PX"} + {:value :percent :label "%"}] + :on-change #(set-column-type type index %)}]]] - [:button - {:class (stl/css :remove-track-btn) - :on-click #(remove-element type index)} - i/remove-refactor]] - - [:div.column-info - {:ref dref - :class (dom/classnames - :dnd-over-top (or (= (:over dprops) :top) - (= (:over dprops) :center)) - :dnd-over-bot (= (:over dprops) :bot)) - :on-pointer-enter pointer-enter - :on-pointer-leave pointer-leave} - [:div.direction-grid-icon - (if is-col? - i/layout-rows - i/layout-columns)] - - [:div.grid-column-value - [:> numeric-input* {:no-validate true - :value (:value column) - :on-change #(set-column-value type index %) - :placeholder "--" - :disabled (= :auto (:type column))}]] - [:div.grid-column-unit - [:& select - {:class "grid-column-unit-selector" - :default-value (:type column) - :options [{:value :flex :label "FR"} - {:value :auto :label "AUTO"} - {:value :fixed :label "PX"} - {:value :percent :label "%"}] - :on-change #(set-column-type type index %)}]] - [:button.remove-grid-column - {:on-click #(remove-element type index)} - i/minus]]))) + [:button {:class (stl/css :remove-track-btn) + :on-click #(remove-element type index)} + i/remove-refactor]])) (mf/defc grid-columns-row [{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type remove-element reorder-track hover-track on-select-track] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - column-num (count column-values) + (let [column-num (count column-values) direction (if (> column-num 1) (if is-col? "Columns " "Rows ") (if is-col? "Column " "Row ")) track-name (dm/str direction (if (= column-num 0) " - empty" column-num)) track-detail (str/join ", " (map manage-values column-values)) - generated-name (dm/str direction (if (= column-num 0) " - empty" (dm/str column-num " (" track-detail ")"))) type (if is-col? :column :row) @@ -1087,61 +666,36 @@ (when-not expanded? (toggle)) (add-new-element type ctl/default-track-value))] - (if new-css-system - [:div {:class (stl/css :grid-tracks)} - [:div {:class (stl/css :grid-track-header)} - [:button {:class (stl/css :expand-icon) :on-click toggle} i/menu-refactor] - [:div {:class (stl/css :track-title) :on-click toggle} - [:div {:class (stl/css :track-name) :title track-name} track-name] - [:div {:class (stl/css :track-detail) :title track-detail} track-detail]] - [:button {:class (stl/css :add-column) :on-click add-track} i/add-refactor]] + [:div {:class (stl/css :grid-tracks)} + [:div {:class (stl/css :grid-track-header)} + [:button {:class (stl/css :expand-icon) :on-click toggle} i/menu-refactor] + [:div {:class (stl/css :track-title) :on-click toggle} + [:div {:class (stl/css :track-name) :title track-name} track-name] + [:div {:class (stl/css :track-detail) :title track-detail} track-detail]] + [:button {:class (stl/css :add-column) :on-click add-track} i/add-refactor]] - (when expanded? - [:& h/sortable-container {} - [:div {:class (stl/css :grid-tracks-info-container)} - (for [[index column] (d/enumerate column-values)] - [:& grid-track-info {:key (dm/str index "-" (name type)) - :type type - :is-col? is-col? - :index index - :column column - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track - :on-select-track on-select-track}])]])] - - [:div.grid-columns - [:div.grid-columns-header - [:button.expand-icon {:on-click toggle} i/actions] - [:div.columns-info {:title generated-name :on-click toggle} generated-name] - [:button.add-column {:on-click add-track} i/plus]] - - (when expanded? - [:& h/sortable-container {} - [:div.columns-info-wrapper - (for [[index column] (d/enumerate column-values)] - [:& grid-track-info {:key (dm/str index "-" (name type)) - :type type - :is-col? is-col? - :index index - :column column - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track - :on-select-track on-select-track}])]])]))) + (when expanded? + [:& h/sortable-container {} + [:div {:class (stl/css :grid-tracks-info-container)} + (for [[index column] (d/enumerate column-values)] + [:& grid-track-info {:key (dm/str index "-" (name type)) + :type type + :is-col? is-col? + :index index + :column column + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track + :on-select-track on-select-track}])]])])) ;; LAYOUT COMPONENT (mf/defc layout-container-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "multiple"]))]} [{:keys [ids values multiple] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - ;; Display + (let [;; Display layout-type (:layout values) has-layout? (some? layout-type) @@ -1194,9 +748,9 @@ set-direction-refactor (mf/use-fn - (mf/deps new-css-system layout-type ids) + (mf/deps layout-type ids) (fn [dir] - (let [dir (if new-css-system (keyword dir) dir)] + (let [dir (keyword dir)] (if (= :flex layout-type) (st/emit! (dwsl/update-layout ids {:layout-flex-dir dir})) (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})))))) @@ -1205,7 +759,7 @@ wrap-type (:layout-wrap-type values) - toggle-wrap-refactor + toggle-wrap (mf/use-fn (mf/deps wrap-type ids) (fn [] @@ -1214,30 +768,12 @@ :wrap)] (st/emit! (dwsl/update-layout ids {:layout-wrap-type type}))))) - set-wrap - (mf/use-fn - (mf/deps ids) - (fn [event] - (let [type (-> (dom/get-current-target event) - (dom/get-data "value") - (keyword))] - (st/emit! (dwsl/update-layout ids {:layout-wrap-type type}))))) - ;; Align items align-items (:layout-align-items values) set-align-items - (mf/use-fn - (mf/deps ids) - (fn [event] - (let [value (-> (dom/get-current-target event) - (dom/get-data "value") - (keyword))] - (st/emit! (dwsl/update-layout ids {:layout-align-items value}))))) - - set-align-items-refactor (mf/use-fn (mf/deps ids) (fn [value] @@ -1248,15 +784,6 @@ justify-content (:layout-justify-content values) set-justify-content - (mf/use-fn - (mf/deps ids) - (fn [event] - (let [value (-> (dom/get-current-target event) - (dom/get-data "value") - (keyword))] - (st/emit! (dwsl/update-layout ids {:layout-justify-content value}))))) - - set-justify-content-refactor (mf/use-fn (mf/deps ids) (fn [value] @@ -1267,17 +794,6 @@ align-content (:layout-align-content values) set-align-content - (mf/use-fn - (mf/deps ids align-content) - (fn [event] - (let [value (-> (dom/get-current-target event) - (dom/get-data "value") - (keyword))] - (if (= align-content value) - (st/emit! (dwsl/update-layout ids {:layout-align-content :stretch})) - (st/emit! (dwsl/update-layout ids {:layout-align-content value})))))) - - set-align-content-refactor (mf/use-fn (mf/deps ids) (fn [value align-content] @@ -1324,9 +840,9 @@ set-direction (mf/use-fn - (mf/deps layout-type ids new-css-system) + (mf/deps layout-type ids) (fn [dir] - (let [dir (cond-> dir new-css-system keyword)] + (let [dir (keyword dir)] (if (= :flex layout-type) (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})) (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})))))) @@ -1337,9 +853,9 @@ set-align-grid (mf/use-fn - (mf/deps ids new-css-system) + (mf/deps ids) (fn [value type] - (let [value (cond-> value new-css-system keyword)] + (let [value (keyword value)] (if (= type :row) (st/emit! (dwsl/update-layout ids {:layout-align-items value})) (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))))) @@ -1352,9 +868,9 @@ set-justify-grid (mf/use-fn - (mf/deps ids new-css-system) + (mf/deps ids) (fn [value type] - (let [value (cond-> value new-css-system keyword)] + (let [value (keyword value)] (if (= type :row) (st/emit! (dwsl/update-layout ids {:layout-justify-content value})) (st/emit! (dwsl/update-layout ids {:layout-align-content value})))))) @@ -1379,246 +895,127 @@ (fn [] (st/emit! (dom/open-new-window cf/grid-help-uri))))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-layout? - :collapsed? (not open?) - :on-collapsed toggle-content - :title "Layout" - :class (stl/css-case :title-spacing-layout (not has-layout?))} - (if (and (not multiple) (:layout values)) - [:div {:class (stl/css :title-actions)} - (when ^boolean grid-enabled? - [:* - [:button {:class (stl/css :add-layout) - :on-click handle-show-layout-dropdown} - i/menu-refactor] + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-layout? + :collapsed? (not open?) + :on-collapsed toggle-content + :title "Layout" + :class (stl/css-case :title-spacing-layout (not has-layout?))} + (if (and (not multiple) (:layout values)) + [:div {:class (stl/css :title-actions)} + (when ^boolean grid-enabled? + [:* + [:button {:class (stl/css :add-layout) + :on-click handle-show-layout-dropdown} + i/menu-refactor] - [:& dropdown {:show show-layout-dropdown? :on-close handle-close-layout-options} - [:div {:class (stl/css :layout-options)} - [:button {:class (stl/css :layout-option) :on-click set-flex} "Flex layout"] - [:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]]) + [:& dropdown {:show show-layout-dropdown? :on-close handle-close-layout-options} + [:div {:class (stl/css :layout-options)} + [:button {:class (stl/css :layout-option) :on-click set-flex} "Flex layout"] + [:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]]) - [:button {:class (stl/css :remove-layout) - :on-click on-remove-layout} - i/remove-refactor]] + [:button {:class (stl/css :remove-layout) + :on-click on-remove-layout} + i/remove-refactor]] - [:div {:class (stl/css :title-actions)} - (if ^boolean grid-enabled? - [:* - [:button {:class (stl/css :add-layout) - :on-click handle-show-layout-dropdown} - i/add-refactor] + [:div {:class (stl/css :title-actions)} + (if ^boolean grid-enabled? + [:* + [:button {:class (stl/css :add-layout) + :on-click handle-show-layout-dropdown} + i/add-refactor] - [:& dropdown {:show show-layout-dropdown? :on-close handle-close-layout-options} - [:div {:class (stl/css :layout-options)} - [:button {:class (stl/css :layout-option) :on-click set-flex} "Flex layout"] - [:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]] + [:& dropdown {:show show-layout-dropdown? :on-close handle-close-layout-options} + [:div {:class (stl/css :layout-options)} + [:button {:class (stl/css :layout-option) :on-click set-flex} "Flex layout"] + [:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]] - [:button {:class (stl/css :add-layout) - :data-value :flex - :on-click on-set-layout} - i/add-refactor])])]] + [:button {:class (stl/css :add-layout) + :data-value :flex + :on-click on-set-layout} + i/add-refactor])])]] - (when (and open? has-layout?) - (when (not= :multiple layout-type) - (case layout-type - :flex - [:div {:class (stl/css :flex-layout-menu)} - [:div {:class (stl/css :first-row)} - [:& align-row {:is-col? is-col? - :align-items align-items - :on-change set-align-items-refactor}] + (when (and open? has-layout?) + (when (not= :multiple layout-type) + (case layout-type + :flex + [:div {:class (stl/css :flex-layout-menu)} + [:div {:class (stl/css :first-row)} + [:& align-row {:is-col? is-col? + :align-items align-items + :on-change set-align-items}] - [:& direction-row-flex {:on-change set-direction-refactor - :saved-dir saved-dir}] + [:& direction-row-flex {:on-change set-direction-refactor + :saved-dir saved-dir}] - [:& wrap-row {:wrap-type wrap-type - :on-click toggle-wrap-refactor}]] + [:& wrap-row {:wrap-type wrap-type + :on-click toggle-wrap}]] - [:div {:class (stl/css :second-row :help-button-wrapper)} - [:& justify-content-row {:is-col? is-col? - :justify-content justify-content - :on-change set-justify-content-refactor}] + [:div {:class (stl/css :second-row :help-button-wrapper)} + [:& justify-content-row {:is-col? is-col? + :justify-content justify-content + :on-change set-justify-content}] - [:button {:on-click handle-open-flex-help - :class (stl/css :help-button)} i/help-refactor]] - (when (= :wrap wrap-type) - [:div {:class (stl/css :third-row)} - [:& align-content-row {:is-col? is-col? - :align-content align-content - :on-change set-align-content-refactor}]]) - [:div {:class (stl/css :forth-row)} - [:& gap-section {:is-col? is-col? - :wrap-type wrap-type - :gap-selected? gap-selected? - :on-change set-gap - :gap-value (:layout-gap values)}] + [:button {:on-click handle-open-flex-help + :class (stl/css :help-button)} i/help-refactor]] + (when (= :wrap wrap-type) + [:div {:class (stl/css :third-row)} + [:& align-content-row {:is-col? is-col? + :align-content align-content + :on-change set-align-content}]]) + [:div {:class (stl/css :forth-row)} + [:& gap-section {:is-col? is-col? + :wrap-type wrap-type + :gap-selected? gap-selected? + :on-change set-gap + :gap-value (:layout-gap values)}] - [:& padding-section {:values values - :on-change-style change-padding-type - :on-change on-padding-change}]]] + [:& padding-section {:values values + :on-change-style change-padding-type + :on-change on-padding-change}]]] - :grid - [:div {:class (stl/css :grid-layout-menu)} - (when (= 1 (count ids)) - [:div {:class (stl/css :edit-grid-wrapper)} - [:& grid-edit-mode {:id (first ids)}] - [:button {:on-click handle-open-grid-help - :class (stl/css :help-button)} i/help-refactor]]) - [:div {:class (stl/css :row :first-row)} - [:div {:class (stl/css :direction-edit)} - [:div {:class (stl/css :direction)} - [:& direction-row-grid {:saved-dir saved-grid-dir - :on-change set-direction}]]] + :grid + [:div {:class (stl/css :grid-layout-menu)} + (when (= 1 (count ids)) + [:div {:class (stl/css :edit-grid-wrapper)} + [:& grid-edit-mode {:id (first ids)}] + [:button {:on-click handle-open-grid-help + :class (stl/css :help-button)} i/help-refactor]]) + [:div {:class (stl/css :row :first-row)} + [:div {:class (stl/css :direction-edit)} + [:div {:class (stl/css :direction)} + [:& direction-row-grid {:saved-dir saved-grid-dir + :on-change set-direction}]]] - [:& align-grid-row {:is-col? false - :align-items align-items-row - :set-align set-align-grid}] + [:& align-grid-row {:is-col? false + :align-items align-items-row + :set-align set-align-grid}] - [:& align-grid-row {:is-col? true - :align-items align-items-column - :set-align set-align-grid}]] + [:& align-grid-row {:is-col? true + :align-items align-items-column + :set-align set-align-grid}]] - [:div {:class (stl/css :row :grid-layout-align)} - [:& justify-grid-row {:is-col? true - :justify-items grid-justify-content-column - :set-justify set-justify-grid}] - [:& justify-grid-row {:is-col? false - :justify-items grid-justify-content-row - :set-justify set-justify-grid}]]] - nil)))] - - [:div.element-set - [:div.element-set-title - [:* - [:span "Layout"] - - (if ^boolean grid-enabled? - [:div.title-actions - [:div.layout-btns - [:button {:on-click set-flex - :class (dom/classnames - :active (= :flex layout-type))} "Flex"] - [:button {:on-click set-grid - :class (dom/classnames - :active (= :grid layout-type))} "Grid"]] - - (when (and (not multiple) (:layout values)) - [:button.remove-layout {:on-click on-remove-layout} i/minus])] - - [:div.title-actions - (if (and (not multiple) (:layout values)) - [:button.remove-layout {:on-click on-remove-layout} i/minus] - [:button.add-page {:data-value :flex - :on-click on-set-layout} i/close])])]] - - (when (:layout values) - (when (not= :multiple layout-type) - (case layout-type - :flex - - [:div.element-set-content.layout-menu - [:div.layout-row - [:div.direction-wrap.row-title "Direction"] - [:div.btn-wrapper - [:div.direction - [:& direction-row-flex {:on-change set-direction - :saved-dir saved-dir}]] - - [:div.wrap-type - [:& wrap-row {:wrap-type wrap-type - :on-click set-wrap}]]]] - - (when (= :wrap wrap-type) - [:div.layout-row - [:div.align-content.row-title "Content"] - [:div.btn-wrapper.align-content - [:& align-content-row {:is-col? is-col? - :align-content align-content - :on-change set-align-content}]]]) - - [:div.layout-row - [:div.align-items.row-title "Align"] - [:div.btn-wrapper - [:& align-row {:is-col? is-col? - :align-items align-items - :on-change set-align-items}]]] - - [:div.layout-row - [:div.justify-content.row-title "Justify"] - [:div.btn-wrapper.justify-content - [:& justify-content-row {:is-col? is-col? - :justify-content justify-content - :on-change set-justify-content}]]] - - [:& gap-section {:is-col? is-col? - :wrap-type wrap-type - :gap-selected? gap-selected? - :on-change set-gap - :gap-value (:layout-gap values)}] - - [:& padding-section {:values values - :on-change-style change-padding-type - :on-change on-padding-change}]] - - :grid - - [:div.element-set-content.layout-menu - [:div.layout-row - [:div.direction-wrap.row-title "Direction"] - [:div.btn-wrapper - [:div.direction - [:* - (for [dir [:row :column]] - [:& direction-btn {:key (d/name dir) - :dir dir - :saved-dir saved-grid-dir - :on-click set-direction - :icon? true}])]] - - (when (= 1 (count ids)) - [:div.edit-mode - [:& grid-edit-mode {:id (first ids)}]])]] - - [:div.layout-row - [:div.align-items-grid.row-title "Items"] - [:div.btn-wrapper.align-grid-items - [:& align-grid-row {:is-col? false - :align-items align-items-row - :set-align set-align-grid}] - - [:& align-grid-row {:is-col? true - :align-items align-items-column - :set-align set-align-grid}]]] - - [:div.layout-row - [:div.jusfiy-content-grid.row-title "Content"] - [:div.btn-wrapper.align-grid-content - [:& justify-grid-row {:is-col? true - :justify-items grid-justify-content-column - :set-justify set-justify-grid}] - [:& justify-grid-row {:is-col? false - :justify-items grid-justify-content-row - :set-justify set-justify-grid}]]]] - - ;; Default if not grid or flex - nil)))]))) + [:div {:class (stl/css :row :grid-layout-align)} + [:& justify-grid-row {:is-col? true + :justify-items grid-justify-content-column + :set-justify set-justify-grid}] + [:& justify-grid-row {:is-col? false + :justify-items grid-justify-content-row + :set-justify set-justify-grid}]]] + nil)))])) (mf/defc grid-layout-edition {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]} [{:keys [ids values] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - ;; Gap + (let [;; Gap gap-selected? (mf/use-state :none) saved-grid-dir (:layout-grid-dir values) set-direction (fn [dir] - (let [dir (if new-css-system (keyword dir) dir)] + (let [dir (keyword dir)] (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})))) set-gap @@ -1650,9 +1047,9 @@ set-align-grid (mf/use-fn - (mf/deps ids new-css-system) + (mf/deps ids) (fn [value type] - (let [value (cond-> value new-css-system keyword)] + (let [value (keyword value)] (if (= type :row) (st/emit! (dwsl/update-layout ids {:layout-align-items value})) (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))))) @@ -1664,9 +1061,9 @@ set-justify-grid (mf/use-fn - (mf/deps ids new-css-system) + (mf/deps ids) (fn [value type] - (let [value (cond-> value new-css-system keyword)] + (let [value (keyword value)] (if (= type :row) (st/emit! (dwsl/update-layout ids {:layout-justify-content value})) (st/emit! (dwsl/update-layout ids {:layout-align-content value})))))) @@ -1743,141 +1140,70 @@ (fn [] (st/emit! (dwge/locate-board (first ids)))))] - (if new-css-system - [:div {:class (stl/css :grid-layout-menu)} - [:div {:class (stl/css :row)} - [:div {:class (stl/css :grid-layout-menu-title)} "GRID LAYOUT"] - [:button {:on-click handle-open-grid-help - :class (stl/css :help-button)} i/help-refactor] - [:button {:class (stl/css :exit-btn) - :on-click #(st/emit! udw/clear-edition-mode)} - (tr "workspace.layout_grid.editor.options.exit")]] + [:div {:class (stl/css :grid-layout-menu)} + [:div {:class (stl/css :row)} + [:div {:class (stl/css :grid-layout-menu-title)} "GRID LAYOUT"] + [:button {:on-click handle-open-grid-help + :class (stl/css :help-button)} i/help-refactor] + [:button {:class (stl/css :exit-btn) + :on-click #(st/emit! udw/clear-edition-mode)} + (tr "workspace.layout_grid.editor.options.exit")]] - [:div {:class (stl/css :row :first-row)} - [:div {:class (stl/css :direction-edit)} - [:div {:class (stl/css :direction)} - [:& direction-row-grid {:saved-dir saved-grid-dir - :on-change set-direction}]]] + [:div {:class (stl/css :row :first-row)} + [:div {:class (stl/css :direction-edit)} + [:div {:class (stl/css :direction)} + [:& direction-row-grid {:saved-dir saved-grid-dir + :on-change set-direction}]]] - [:& align-grid-row {:is-col? false - :align-items align-items-row - :set-align set-align-grid}] + [:& align-grid-row {:is-col? false + :align-items align-items-row + :set-align set-align-grid}] - [:& align-grid-row {:is-col? true - :align-items align-items-column - :set-align set-align-grid}]] + [:& align-grid-row {:is-col? true + :align-items align-items-column + :set-align set-align-grid}]] - [:div {:class (stl/css :row :grid-layout-align)} - [:& justify-grid-row {:is-col? true - :justify-items grid-justify-content-column - :set-justify set-justify-grid}] - [:& justify-grid-row {:is-col? false - :justify-items grid-justify-content-row - :set-justify set-justify-grid}] + [:div {:class (stl/css :row :grid-layout-align)} + [:& justify-grid-row {:is-col? true + :justify-items grid-justify-content-column + :set-justify set-justify-grid}] + [:& justify-grid-row {:is-col? false + :justify-items grid-justify-content-row + :set-justify set-justify-grid}] - [:button {:on-click handle-locate-grid - :class (stl/css :locate-button)} - i/locate-refactor]] - [:div {:class (stl/css :row :grid-tracks-row)} - [:& grid-columns-row {:is-col? true - :expanded? @grid-columns-open? - :toggle toggle-columns-info - :column-values column-grid-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track - :on-select-track handle-select-track}] + [:button {:on-click handle-locate-grid + :class (stl/css :locate-button)} + i/locate-refactor]] + [:div {:class (stl/css :row :grid-tracks-row)} + [:& grid-columns-row {:is-col? true + :expanded? @grid-columns-open? + :toggle toggle-columns-info + :column-values column-grid-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track + :on-select-track handle-select-track}] - [:& grid-columns-row {:is-col? false - :expanded? @grid-rows-open? - :toggle toggle-rows-info - :column-values rows-grid-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track - :on-select-track handle-select-track}]] - [:div {:class (stl/css :row)} - [:& gap-section {:gap-selected? gap-selected? - :on-change set-gap - :gap-value (:layout-gap values)}]] + [:& grid-columns-row {:is-col? false + :expanded? @grid-rows-open? + :toggle toggle-rows-info + :column-values rows-grid-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track + :on-select-track handle-select-track}]] + [:div {:class (stl/css :row)} + [:& gap-section {:gap-selected? gap-selected? + :on-change set-gap + :gap-value (:layout-gap values)}]] - [:div {:class (stl/css :row :padding-section)} - [:& padding-section {:values values - :on-change-style change-padding-type - :on-change on-padding-change}]]] - - [:div.element-set - [:div.element-set-title - [:span "Grid Layout"]] - - [:div.element-set-content.layout-menu - [:div.layout-row - [:div.direction-wrap.row-title "Direction"] - [:div.btn-wrapper - [:div.direction - (for [dir [:row :column]] - [:& direction-btn {:key (d/name dir) - :dir dir - :saved-dir saved-grid-dir - :on-click set-direction - :icon? true}])] - - (when (= 1 (count ids)) - [:div.edit-mode - [:& grid-edit-mode {:id (first ids)}]])]] - - [:div.layout-row - [:div.align-items-grid.row-title "Items"] - [:div.btn-wrapper.align-grid - [:& align-grid-row {:is-col? false - :align-items align-items-row - :set-align set-align-grid}] - - [:& align-grid-row {:is-col? true - :align-items align-items-column - :set-align set-align-grid}]]] - - [:div.layout-row - [:div.jusfiy-content-grid.row-title "Content"] - [:div.btn-wrapper.align-grid-content - [:& justify-grid-row {:is-col? true - :justify-items grid-justify-content-row - :set-justify set-justify-grid}] - [:& justify-grid-row {:is-col? false - :justify-items grid-justify-content-column - :set-justify set-justify-grid}]]] - [:& grid-columns-row {:is-col? true - :expanded? @grid-columns-open? - :toggle toggle-columns-info - :column-values column-grid-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track}] - - [:& grid-columns-row {:is-col? false - :expanded? @grid-rows-open? - :toggle toggle-rows-info - :column-values rows-grid-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track}] - - [:& gap-section {:gap-selected? gap-selected? - :on-change set-gap - :gap-value (:layout-gap values)}] - - [:& padding-section {:values values - :on-change-style change-padding-type - :on-change on-padding-change}]]]))) + [:div {:class (stl/css :row :padding-section)} + [:& padding-section {:values values + :on-change-style change-padding-type + :on-change on-padding-change}]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss index 1bee7524d6..cc51a740bd 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss @@ -174,7 +174,7 @@ .grid-layout-menu-title { flex: 1; font-size: $fs-11; - color: $df-primary; + color: var(--title-foreground-color-hover); } .edit-mode-btn { @@ -246,9 +246,6 @@ border-right: $s-1 solid var(--panel-background-color); } - .track-info-unit { - } - .track-info-unit-selector { border-radius: 0 $br-8 $br-8 0; width: $s-96; diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index 4162175b7a..8a028b2ff0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -17,9 +17,8 @@ [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon get-layout-flex-icon-refactor]] + [app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -40,8 +39,7 @@ (mf/defc margin-section [{:keys [values change-margin-style on-margin-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - margin-type (or (:layout-item-margin-type values) :simple) + (let [margin-type (or (:layout-item-margin-type values) :simple) m1 (when (and (not (= :multiple (:layout-item-margin values))) (= (dm/get-in values [:layout-item-margin :m1]) (dm/get-in values [:layout-item-margin :m3]))) @@ -63,158 +61,99 @@ ;;on destroy component (select-margins false false false false)))) - (if new-css-system - [:div {:class (stl/css :margin-row)} - [:div {:class (stl/css :inputs-wrapper)} - (cond - (= margin-type :simple) - [:div {:class (stl/css :margin-simple)} - [:div {:class (stl/css :vertical-margin) - :title "Vertical margin"} - [:span {:class (stl/css :icon)} - i/margin-top-bottom-refactor] - [:> numeric-input* {:className (stl/css :numeric-input) - :placeholder "--" - :nillable true - :value m1 - :on-focus (fn [event] - (select-margins true false true false) - (dom/select-target event)) - :on-change (partial on-margin-change :simple :m1) - :on-blur #(select-margins false false false false)}]] + [:div {:class (stl/css :margin-row)} + [:div {:class (stl/css :inputs-wrapper)} + (cond + (= margin-type :simple) + [:div {:class (stl/css :margin-simple)} + [:div {:class (stl/css :vertical-margin) + :title "Vertical margin"} + [:span {:class (stl/css :icon)} + i/margin-top-bottom-refactor] + [:> numeric-input* {:className (stl/css :numeric-input) + :placeholder "--" + :nillable true + :value m1 + :on-focus (fn [event] + (select-margins true false true false) + (dom/select-target event)) + :on-change (partial on-margin-change :simple :m1) + :on-blur #(select-margins false false false false)}]] - [:div {:class (stl/css :horizontal-margin) - :title "Horizontal margin"} - [:span {:class (stl/css :icon)} - i/margin-left-right-refactor] - [:> numeric-input* {:className (stl/css :numeric-input) - :placeholder "--" - :on-focus (fn [event] - (select-margins false true false true) - (dom/select-target event)) - :on-change (partial on-margin-change :simple :m2) - :on-blur #(select-margins false false false false) - :nillable true - :value m2}]]] + [:div {:class (stl/css :horizontal-margin) + :title "Horizontal margin"} + [:span {:class (stl/css :icon)} + i/margin-left-right-refactor] + [:> numeric-input* {:className (stl/css :numeric-input) + :placeholder "--" + :on-focus (fn [event] + (select-margins false true false true) + (dom/select-target event)) + :on-change (partial on-margin-change :simple :m2) + :on-blur #(select-margins false false false false) + :nillable true + :value m2}]]] - (= margin-type :multiple) - [:div {:class (stl/css :margin-multiple)} - [:div {:class (stl/css :top-margin) - :title "Top margin"} - [:span {:class (stl/css :icon)} - i/margin-top-refactor] - [:> numeric-input* {:className (stl/css :numeric-input) - :placeholder "--" - :on-focus (fn [event] - (select-margin :m1) - (dom/select-target event)) - :on-change (partial on-margin-change :multiple :m1) - :on-blur #(select-margins false false false false) - :nillable true - :value (:m1 (:layout-item-margin values))}]] - [:div {:class (stl/css :right-margin) - :title "Right margin"} - [:span {:class (stl/css :icon)} - i/margin-right-refactor] - [:> numeric-input* {:className (stl/css :numeric-input) - :placeholder "--" - :on-focus (fn [event] - (select-margin :m2) - (dom/select-target event)) - :on-change (partial on-margin-change :multiple :m2) - :on-blur #(select-margins false false false false) - :nillable true - :value (:m2 (:layout-item-margin values))}]] + (= margin-type :multiple) + [:div {:class (stl/css :margin-multiple)} + [:div {:class (stl/css :top-margin) + :title "Top margin"} + [:span {:class (stl/css :icon)} + i/margin-top-refactor] + [:> numeric-input* {:className (stl/css :numeric-input) + :placeholder "--" + :on-focus (fn [event] + (select-margin :m1) + (dom/select-target event)) + :on-change (partial on-margin-change :multiple :m1) + :on-blur #(select-margins false false false false) + :nillable true + :value (:m1 (:layout-item-margin values))}]] + [:div {:class (stl/css :right-margin) + :title "Right margin"} + [:span {:class (stl/css :icon)} + i/margin-right-refactor] + [:> numeric-input* {:className (stl/css :numeric-input) + :placeholder "--" + :on-focus (fn [event] + (select-margin :m2) + (dom/select-target event)) + :on-change (partial on-margin-change :multiple :m2) + :on-blur #(select-margins false false false false) + :nillable true + :value (:m2 (:layout-item-margin values))}]] - [:div {:class (stl/css :bottom-margin) - :title "Bottom margin"} - [:span {:class (stl/css :icon)} - i/margin-bottom-refactor] - [:> numeric-input* {:className (stl/css :numeric-input) - :placeholder "--" - :on-focus (fn [event] - (select-margin :m3) - (dom/select-target event)) - :on-change (partial on-margin-change :multiple :m3) - :on-blur #(select-margins false false false false) - :nillable true - :value (:m3 (:layout-item-margin values))}]] - [:div {:class (stl/css :left-margin) - :title "Left margin"} - [:span {:class (stl/css :icon)} - i/margin-left-refactor] - [:> numeric-input* {:className (stl/css :numeric-input) - :placeholder "--" - :on-focus (fn [event] - (select-margin :m4) - (dom/select-target event)) - :on-change (partial on-margin-change :multiple :m4) - :on-blur #(select-margins false false false false) - :nillable true - :value (:m4 (:layout-item-margin values))}]]])] - [:button {:class (stl/css-case :margin-mode true - :selected (= margin-type :multiple)) - :title "Margin - multiple" - :on-click #(change-margin-style (if (= margin-type :multiple) :simple :multiple))} - i/margin-refactor]] - [:div.margin-row - (cond - (= margin-type :simple) - - [:div.margin-item-group - [:div.margin-item.tooltip.tooltip-bottom-left - {:alt "Vertical margin"} - [:span.icon i/auto-margin-both-sides] - [:> numeric-input* - {:placeholder "--" - :on-focus (fn [event] - (select-margins true false true false) - (dom/select-target event)) - :on-change (partial on-margin-change :simple :m1) - :on-blur #(select-margins false false false false) - :nillable true - :value m1}]] - - [:div.margin-item.tooltip.tooltip-bottom-left - {:alt "Horizontal margin"} - [:span.icon.rotated i/auto-margin-both-sides] - [:> numeric-input* - {:placeholder "--" - :on-focus (fn [event] - (select-margins false true false true) - (dom/select-target event)) - :on-change (partial on-margin-change :simple :m2) - :on-blur #(select-margins false false false false) - :nillable true - :value m2}]]] - - (= margin-type :multiple) - [:div.wrapper - (for [num [:m1 :m2 :m3 :m4]] - [:div.tooltip.tooltip-bottom - {:key (dm/str "margin-" (d/name num)) - :alt (case num - :m1 "Top" - :m2 "Right" - :m3 "Bottom" - :m4 "Left")} - [:div.input-element.auto - [:> numeric-input* - {:placeholder "--" - :on-focus (fn [event] - (select-margin num) - (dom/select-target event)) - :on-change (partial on-margin-change :multiple num) - :on-blur #(select-margins false false false false) - :nillable true - :value (num (:layout-item-margin values))}]]])]) - - [:div.margin-item-icons - [:div.margin-item-icon.tooltip.tooltip-bottom-left - {:class (dom/classnames :selected (= margin-type :multiple)) - :alt "Margin - multiple" - :on-click #(change-margin-style (if (= margin-type :multiple) :simple :multiple))} - i/auto-margin]]]))) + [:div {:class (stl/css :bottom-margin) + :title "Bottom margin"} + [:span {:class (stl/css :icon)} + i/margin-bottom-refactor] + [:> numeric-input* {:className (stl/css :numeric-input) + :placeholder "--" + :on-focus (fn [event] + (select-margin :m3) + (dom/select-target event)) + :on-change (partial on-margin-change :multiple :m3) + :on-blur #(select-margins false false false false) + :nillable true + :value (:m3 (:layout-item-margin values))}]] + [:div {:class (stl/css :left-margin) + :title "Left margin"} + [:span {:class (stl/css :icon)} + i/margin-left-refactor] + [:> numeric-input* {:className (stl/css :numeric-input) + :placeholder "--" + :on-focus (fn [event] + (select-margin :m4) + (dom/select-target event)) + :on-change (partial on-margin-change :multiple :m4) + :on-blur #(select-margins false false false false) + :nillable true + :value (:m4 (:layout-item-margin values))}]]])] + [:button {:class (stl/css-case :margin-mode true + :selected (= margin-type :multiple)) + :title "Margin - multiple" + :on-click #(change-margin-style (if (= margin-type :multiple) :simple :multiple))} + i/margin-refactor]])) (mf/defc element-behaviour-horizontal [{:keys [auto? fill? layout-item-sizing on-change] :as props}] @@ -270,112 +209,46 @@ :id "behaviour-v-auto"}])]]) (mf/defc element-behaviour - [{:keys [auto? fill? layout-item-h-sizing layout-item-v-sizing on-change-behaviour-h-refactor on-change-behaviour-v-refactor on-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - - (if new-css-system - [:div {:class (stl/css-case :behaviour-menu true - :wrap (and fill? auto?))} - [:& element-behaviour-horizontal {:auto? auto? - :fill? fill? - :layout-item-sizing layout-item-h-sizing - :on-change on-change-behaviour-h-refactor}] - [:& element-behaviour-vertical {:auto? auto? - :fill? fill? - :layout-item-sizing layout-item-v-sizing - :on-change on-change-behaviour-v-refactor}]] - - [:div.btn-wrapper - {:class (when (and fill? auto?) "wrap")} - [:div.layout-behavior.horizontal - [:button.behavior-btn.tooltip.tooltip-bottom - {:alt "Fix width" - :class (dom/classnames :active (= layout-item-h-sizing :fix)) - :data-direction :h - :data-value :fix - :on-click on-change} - i/auto-fix-layout] - (when fill? - [:button.behavior-btn.tooltip.tooltip-bottom - {:alt "Width 100%" - :class (dom/classnames :active (= layout-item-h-sizing :fill)) - :data-direction :h - :data-value :fill - :on-click on-change} - i/auto-fill]) - (when auto? - [:button.behavior-btn.tooltip.tooltip-bottom - {:alt "Fit content" - :class (dom/classnames :active (= layout-item-h-sizing :auto)) - :data-direction :h - :data-value :auto - :on-click on-change} - i/auto-hug])] - - [:div.layout-behavior - [:button.behavior-btn.tooltip.tooltip-bottom - {:alt "Fix height" - :class (dom/classnames :active (= layout-item-v-sizing :fix)) - :data-direction :v - :data-value :fix - :on-click on-change} - i/auto-fix-layout] - (when fill? - [:button.behavior-btn.tooltip.tooltip-bottom-left - {:alt "Height 100%" - :class (dom/classnames :active (= layout-item-v-sizing :fill)) - :data-direction :v - :data-value :fill - :on-click on-change} - i/auto-fill]) - (when auto? - [:button.behavior-btn.tooltip.tooltip-bottom-left - {:alt "Fit content" - :class (dom/classnames :active (= layout-item-v-sizing :auto)) - :data-direction :v - :data-value :auto - :on-click on-change} - i/auto-hug])]]))) + [{:keys [auto? + fill? + layout-item-h-sizing + layout-item-v-sizing + on-change-behaviour-h-refactor + on-change-behaviour-v-refactor] :as props}] + [:div {:class (stl/css-case :behaviour-menu true + :wrap (and fill? auto?))} + [:& element-behaviour-horizontal {:auto? auto? + :fill? fill? + :layout-item-sizing layout-item-h-sizing + :on-change on-change-behaviour-h-refactor}] + [:& element-behaviour-vertical {:auto? auto? + :fill? fill? + :layout-item-sizing layout-item-v-sizing + :on-change on-change-behaviour-v-refactor}]]) (mf/defc align-self-row [{:keys [is-col? align-self on-change] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - dir-v [:start :center :end #_:stretch #_:baseline]] - (if new-css-system - [:& radio-buttons {:selected (d/name align-self) - :on-change on-change - :name "flex-align-self"} - [:& radio-button {:value "start" - :icon (get-layout-flex-icon-refactor :align-self :start is-col?) - :title "Align self start" - :id "align-self-start"}] - [:& radio-button {:value "center" - :icon (get-layout-flex-icon-refactor :align-self :center is-col?) - :title "Align self center" - :id "align-self-center"}] - [:& radio-button {:value "end" - :icon (get-layout-flex-icon-refactor :align-self :end is-col?) - :title "Align self end" - :id "align-self-end"}]] - - [:div.align-self-style - (for [align dir-v] - [:button.align-self.tooltip.tooltip-bottom - {:class (dom/classnames :active (= align-self align) - :tooltip-bottom-left (not= align :start) - :tooltip-bottom (= align :start)) - :alt (dm/str "Align self " (d/name align)) - :data-value align - :on-click on-change - :key (str "align-self" align)} - (get-layout-flex-icon :align-self align is-col?)])]))) + [:& radio-buttons {:selected (d/name align-self) + :on-change on-change + :name "flex-align-self"} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :align-self :start is-col?) + :title "Align self start" + :id "align-self-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :align-self :center is-col?) + :title "Align self center" + :id "align-self-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :align-self :end is-col?) + :title "Align self end" + :id "align-self-end"}]]) (mf/defc layout-item-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "is-layout-child?" "is-grid-parent?" "is-flex-parent?"]))]} [{:keys [ids values is-layout-child? is-layout-container? is-grid-parent? is-flex-parent?] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) + (let [selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) selection-parents (mf/deref selection-parents-ref) is-absolute? (:layout-item-absolute values) @@ -408,17 +281,6 @@ "Layout element") set-align-self - (mf/use-fn - (mf/deps ids align-self) - (fn [event] - (let [value (-> (dom/get-current-target event) - (dom/get-data "value") - (d/read-string))] - (if (= align-self value) - (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) - (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))))) - - set-align-self-refactor (mf/use-fn (mf/deps ids align-self) (fn [value] @@ -464,7 +326,7 @@ (mf/use-fn (mf/deps ids) (fn [value] - (let [value (if new-css-system (keyword value) value)] + (let [value (keyword value)] (st/emit! (dwsl/update-layout-child ids {:layout-item-h-sizing value}))))) @@ -472,7 +334,7 @@ (mf/use-fn (mf/deps ids) (fn [value] - (let [value (if new-css-system (keyword value) value)] + (let [value (keyword value)] (st/emit! (dwsl/update-layout-child ids {:layout-item-v-sizing value}))))) ;; Size and position @@ -485,7 +347,7 @@ (mf/use-fn (mf/deps ids) (fn [value] - (let [value (if new-css-system (keyword value) value)] + (let [value (keyword value)] (when (= value :static) (st/emit! (dwsl/update-layout-child ids {:layout-item-z-index nil}))) (st/emit! (dwsl/update-layout-child ids {:layout-item-absolute (= value :absolute)}))))) @@ -498,19 +360,18 @@ (fn [value] (st/emit! (dwsl/update-layout-child ids {:layout-item-z-index value}))))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-content? - :collapsed? (not open?) - :on-collapsed toggle-content - :title title - :class (stl/css-case :title-spacing-layout-element true - :title-spacing-empty (not has-content?))}]] - (when open? - [:div {:class (stl/css :flex-element-menu)} - (when (or is-layout-child? is-absolute?) - [:div {:class (stl/css :row)} + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-content? + :collapsed? (not open?) + :on-collapsed toggle-content + :title title + :class (stl/css-case :title-spacing-layout-element true + :title-spacing-empty (not has-content?))}]] + (when open? + [:div {:class (stl/css :flex-element-menu)} + (when (or is-layout-child? is-absolute?) + [:div {:class (stl/css :row)} [:div {:class (stl/css :position-options)} [:& radio-buttons {:selected (if is-absolute? "absolute" "static") :on-change on-change-position @@ -535,187 +396,93 @@ :nillable true :value (:layout-item-z-index values)}]])]) + [:div {:class (stl/css :row)} + [:& element-behaviour {:fill? is-layout-child? + :auto? is-layout-container? + :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) + :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) + :on-change-behaviour-h-refactor on-change-behaviour-h + :on-change-behaviour-v-refactor on-change-behaviour-v + :on-change on-change-behaviour}]] + + (when (and is-layout-child? is-flex-parent?) [:div {:class (stl/css :row)} - [:& element-behaviour {:fill? is-layout-child? - :auto? is-layout-container? - :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) - :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) - :on-change-behaviour-h-refactor on-change-behaviour-h - :on-change-behaviour-v-refactor on-change-behaviour-v - :on-change on-change-behaviour}]] + [:& align-self-row {:is-col? is-col? + :align-self align-self + :on-changer set-align-self}]]) - (when (and is-layout-child? is-flex-parent?) - [:div {:class (stl/css :row)} - [:& align-self-row {:is-col? is-col? - :align-self align-self - :on-changer set-align-self-refactor}]]) - - (when is-layout-child? - [:div {:class (stl/css :row)} - [:& margin-section {:values values - :change-margin-style change-margin-style - :on-margin-change on-margin-change}]]) - - (when (or (= (:layout-item-h-sizing values) :fill) - (= (:layout-item-v-sizing values) :fill)) - [:div {:class (stl/css :row)} - [:div {:class (stl/css :advanced-options)} - (when (= (:layout-item-h-sizing values) :fill) - [:div {:class (stl/css :horizontal-fill)} - [:div {:class (stl/css :layout-item-min-w) - :title (tr "workspace.options.layout-item.layout-item-min-w")} - - [:span {:class (stl/css :icon-text)} - "MIN W"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-min-w) - :value (get values :layout-item-min-w) - :nillable true}]] - - [:div {:class (stl/css :layout-item-max-w) - :title (tr "workspace.options.layout-item.layout-item-max-w")} - [:span {:class (stl/css :icon-text)} - "MAX W"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-max-w) - :value (get values :layout-item-max-w) - :nillable true}]]]) - (when (= (:layout-item-v-sizing values) :fill) - [:div {:class (stl/css :vertical-fill)} - [:div {:class (stl/css :layout-item-min-h) - :title (tr "workspace.options.layout-item.layout-item-min-h")} - - [:span {:class (stl/css :icon-text)} - "MIN H"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-min-h) - :value (get values :layout-item-min-h) - :nillable true}]] - - [:div {:class (stl/css :layout-item-max-h) - :title (tr "workspace.options.layout-item.layout-item-max-h")} - - [:span {:class (stl/css :icon-text)} - "MAX H"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-max-h) - :value (get values :layout-item-max-h) - :nillable true}]]])]])])] - - - [:div.element-set - [:div.element-set-title - [:span (cond - (and is-layout-container? (not is-layout-child?)) - "Flex board" - - is-flex-parent? - "Flex element" - - is-grid-parent? - "Grid element" - - :else - "Layout element")]] - - [:div.element-set-content.layout-item-menu - (when (or is-layout-child? is-absolute?) - [:div.layout-row - [:div.row-title.sizing "Position"] - [:div.btn-wrapper - [:div.absolute - [:button.behavior-btn.tooltip.tooltip-bottom - {:alt "Static" - :class (dom/classnames :active (not (:layout-item-absolute values))) - :on-click #(on-change-position :static)} - "Static"] - [:button.behavior-btn.tooltip.tooltip-bottom - {:alt "Absolute" - :class (dom/classnames :active (and (:layout-item-absolute values) (not= :multiple (:layout-item-absolute values)))) - :on-click #(on-change-position :absolute)} - "Absolute"]] - - [:div.tooltip.tooltip-bottom-left.z-index {:alt "z-index"} - i/layers - [:> numeric-input* - {:placeholder "--" - :on-focus #(dom/select-target %) - :on-change #(on-change-z-index %) - :nillable true - :value (:layout-item-z-index values)}]]]]) - - [:* - [:div.layout-row - [:div.row-title.sizing "Sizing"] - [:& element-behaviour {:fill? is-layout-child? - :auto? is-layout-container? - :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) - :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) - :on-change-behaviour-h-refactor on-change-behaviour-h - :on-change-behaviour-v-refactor on-change-behaviour-v - :on-change on-change-behaviour}]] - - (when (and is-layout-child? is-flex-parent?) - [:div.layout-row - [:div.row-title "Align"] - [:div.btn-wrapper - [:& align-self-row {:is-col? is-col? - :align-self align-self - :on-change set-align-self}]]]) - - (when is-layout-child? + (when is-layout-child? + [:div {:class (stl/css :row)} [:& margin-section {:values values :change-margin-style change-margin-style - :on-margin-change on-margin-change}]) + :on-margin-change on-margin-change}]]) - [:div.advanced-ops-body - [:div.input-wrapper - (for [item (cond-> [] - (= (:layout-item-h-sizing values) :fill) - (conj :layout-item-min-w :layout-item-max-w) + (when (or (= (:layout-item-h-sizing values) :fill) + (= (:layout-item-v-sizing values) :fill)) + [:div {:class (stl/css :row)} + [:div {:class (stl/css :advanced-options)} + (when (= (:layout-item-h-sizing values) :fill) + [:div {:class (stl/css :horizontal-fill)} + [:div {:class (stl/css :layout-item-min-w) + :title (tr "workspace.options.layout-item.layout-item-min-w")} - (= (:layout-item-v-sizing values) :fill) - (conj :layout-item-min-h :layout-item-max-h))] + [:span {:class (stl/css :icon-text)} + "MIN W"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-min-w) + :value (get values :layout-item-min-w) + :nillable true}]] - [:div.tooltip.tooltip-bottom - {:key (d/name item) - :alt (tr (dm/str "workspace.options.layout-item.title." (d/name item))) - :class (dom/classnames "maxH" (= item :layout-item-max-h) - "minH" (= item :layout-item-min-h) - "maxW" (= item :layout-item-max-w) - "minW" (= item :layout-item-min-w))} - [:div.input-element - {:alt (tr (dm/str "workspace.options.layout-item." (d/name item)))} - [:> numeric-input* - {:no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change item) - :value (get values item) - :nillable true}]]])]]]]]))) + [:div {:class (stl/css :layout-item-max-w) + :title (tr "workspace.options.layout-item.layout-item-max-w")} + [:span {:class (stl/css :icon-text)} + "MAX W"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-max-w) + :value (get values :layout-item-max-w) + :nillable true}]]]) + (when (= (:layout-item-v-sizing values) :fill) + [:div {:class (stl/css :vertical-fill)} + [:div {:class (stl/css :layout-item-min-h) + :title (tr "workspace.options.layout-item.layout-item-min-h")} + + [:span {:class (stl/css :icon-text)} + "MIN H"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-min-h) + :value (get values :layout-item-min-h) + :nillable true}]] + + [:div {:class (stl/css :layout-item-max-h) + :title (tr "workspace.options.layout-item.layout-item-max-h")} + + [:span {:class (stl/css :icon-text)} + "MAX H"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-max-h) + :value (get values :layout-item-max-h) + :nillable true}]]])]])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss index 6899664041..a88b10213d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss @@ -8,125 +8,132 @@ .element-set { margin: 0; - .element-title { - .title-spacing-layout-element { - margin: 0 0 $s-4 0; - } - .title-spacing-empty { - padding-left: $s-2; - } +} + +.title-spacing-layout-element { + margin: 0 0 $s-4 0; +} + +.title-spacing-empty { + padding-left: $s-2; +} + +.flex-element-menu { + @include flexColumn; + gap: $s-12; +} + +.behaviour-menu { + display: flex; + gap: $s-4; +} + +.horizontal-behaviour { + &.one-element { + width: $s-28; } - .flex-element-menu { - @include flexColumn; - gap: $s-12; + &.two-element { + width: $s-60; + } + &.three-element { + width: $s-92; + } +} - .behaviour-menu { - display: flex; - gap: $s-4; - .horizontal-behaviour { - &.one-element { - width: $s-28; - } - &.two-element { - width: $s-60; - } - &.three-element { - width: $s-92; - } - } - .vertical-behaviour { - .rotated { - transform: rotate(90deg); - } - &.one-element { - width: $s-28; - } - &.two-element { - width: $s-60; - } - &.three-element { - width: $s-92; - } - } - } +.vertical-behaviour { + .rotated { + transform: rotate(90deg); + } + &.one-element { + width: $s-28; + } + &.two-element { + width: $s-60; + } + &.three-element { + width: $s-92; + } +} - .z-index-wrapper { - @extend .input-element; - width: $s-60; - } +.z-index-wrapper { + @extend .input-element; + width: $s-60; +} - .row { - display: flex; - gap: $s-4; - } +.row { + display: flex; + gap: $s-4; +} - .position-options { - width: $s-188; - } +.position-options { + width: $s-188; +} - .margin-row { - display: flex; - align-items: flex-start; - gap: $s-4; - .margin-mode { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - &.selected { - background-color: var(--button-tertiary-background-color-active); - color: var(--button-tertiary-foreground-color-active); - svg { - stroke: var(--button-tertiary-foreground-color-active); - } - } - } - .inputs-wrapper { - .margin-simple { - display: flex; - gap: $s-4; - .vertical-margin, - .horizontal-margin { - @extend .input-element; - width: $s-108; - } - } - .margin-multiple { - display: grid; - grid-template-columns: 1fr 1fr; - gap: $s-4; - .top-margin, - .bottom-margin, - .left-margin, - .right-margin { - @extend .input-element; - width: $s-108; - } - } - } - } +.margin-row { + display: flex; + align-items: flex-start; + gap: $s-4; +} - .advanced-options { - @include flexColumn; - .horizontal-fill, - .vertical-fill { - display: flex; - gap: $s-4; - .layout-item-min-w, - .layout-item-min-h, - .layout-item-max-w, - .layout-item-max-h { - @extend .input-element; - width: $s-108; - .icon-text { - justify-content: flex-start; - width: $s-80; - padding-top: $s-2; - } - } - } +.margin-mode { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + &.selected { + background-color: var(--button-tertiary-background-color-active); + color: var(--button-tertiary-foreground-color-active); + svg { + stroke: var(--button-tertiary-foreground-color-active); } } } + +.margin-simple { + display: flex; + gap: $s-4; + .vertical-margin, + .horizontal-margin { + @extend .input-element; + width: $s-108; + } +} + +.margin-multiple { + display: grid; + grid-template-columns: 1fr 1fr; + gap: $s-4; +} + +.top-margin, +.bottom-margin, +.left-margin, +.right-margin { + @extend .input-element; + width: $s-108; +} + +.advanced-options { + @include flexColumn; +} + +.horizontal-fill, +.vertical-fill { + display: flex; + gap: $s-4; +} + +.layout-item-min-w, +.layout-item-min-h, +.layout-item-max-w, +.layout-item-max-h { + @extend .input-element; + width: $s-108; + .icon-text { + justify-content: flex-start; + width: $s-80; + padding-top: $s-2; + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index fc408f592e..0cc61833c6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -21,7 +21,6 @@ [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -75,8 +74,7 @@ {::mf/wrap-props false ::mf/wrap [mf/memo]} [{:keys [ids ids-with-children values type all-types shape]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - options (if (= type :multiple) + (let [options (if (= type :multiple) (reduce #(union %1 %2) (map #(get type->options %) all-types)) (get type->options type)) @@ -193,16 +191,7 @@ :else :vert)) - on-orientation-clicked - (mf/use-fn - (mf/deps ids) - (fn [event] - (let [orientation (-> (dom/get-current-target event) - (dom/get-data "value") - (keyword))] - (st/emit! (udw/change-orientation ids orientation))))) - - on-orientation-change-refactor + on-orientation-change (mf/use-fn (mf/deps ids) (fn [orientation] @@ -348,30 +337,29 @@ ;; restore focus to the newly created numeric-input (let [radius-input (mf/ref-val radius-input-ref)] (dom/focus! radius-input))))) - (if new-css-system - [:div {:class (stl/css :element-set)} - (when (and (options :presets) - (or (nil? all-types) (= (count all-types) 1))) - [:div {:class (stl/css :presets)} - [:div {:class (stl/css-case :presets-wrapper true - :opened show-presets-dropdown?) - :on-click open-presets} - [:span {:class (stl/css :select-name)}(tr "workspace.options.size-presets")] - [:span {:class (stl/css :collapsed-icon)} i/arrow-refactor] + [:div {:class (stl/css :element-set)} + (when (and (options :presets) + (or (nil? all-types) (= (count all-types) 1))) + [:div {:class (stl/css :presets)} + [:div {:class (stl/css-case :presets-wrapper true + :opened show-presets-dropdown?) + :on-click open-presets} + [:span {:class (stl/css :select-name)} (tr "workspace.options.size-presets")] + [:span {:class (stl/css :collapsed-icon)} i/arrow-refactor] - [:& dropdown {:show show-presets-dropdown? - :on-close close-presets} - [:ul {:class (stl/css :custom-select-dropdown)} - (for [size-preset size-presets] - (if-not (:width size-preset) + [:& dropdown {:show show-presets-dropdown? + :on-close close-presets} + [:ul {:class (stl/css :custom-select-dropdown)} + (for [size-preset size-presets] + (if-not (:width size-preset) + [:li {:key (:name size-preset) + :class (stl/css-case :dropdown-element true + :disabled true)} + [:span {:class (stl/css :preset-name)} (:name size-preset)]] + + (let [preset-match (and (= (:width size-preset) (d/parse-integer (:width values) 0)) + (= (:height size-preset) (d/parse-integer (:height values) 0)))] [:li {:key (:name size-preset) - :class (stl/css-case :dropdown-element true - :disabled true)} - [:span {:class (stl/css :preset-name)} (:name size-preset)]] - - (let [preset-match (and (= (:width size-preset) (d/parse-integer (:width values) 0)) - (= (:height size-preset) (d/parse-integer (:height values) 0)))] - [:li {:key (:name size-preset) :class (stl/css-case :dropdown-element true :match preset-match) :data-width (:width size-preset) @@ -383,366 +371,189 @@ (when preset-match [:span {:class (stl/css :check-icon)} i/tick-refactor])])))]]] - [:& radio-buttons {:selected (or (d/name orientation) "") - :on-change on-orientation-change-refactor - :name "frame-otientation"} - [:& radio-button {:icon i/size-vertical-refactor - :value "vert" - :id "size-vertical"}] - [:& radio-button {:icon i/size-horizontal-refactor - :value "horiz" - :id "size-horizontal"}]]]) - (when (options :size) - [:div {:class (stl/css :size)} - [:div {:class (stl/css-case :width true - :disabled disabled-width-sizing?) - :title (tr "workspace.options.width")} - [:span {:class (stl/css :icon-text)} "W"] - [:> numeric-input* {:min 0.01 - :no-validate true - :placeholder "--" - :on-change on-width-change - :disabled disabled-width-sizing? - :className (stl/css :numeric-input) - :value (:width values)}]] - [:div {:class (stl/css-case :height true - :disabled disabled-height-sizing?) - :title (tr "workspace.options.height")} - [:span {:class (stl/css :icon-text)} "H"] - [:> numeric-input* {:min 0.01 - :no-validate true - :placeholder "--" - :on-change on-height-change - :disabled disabled-height-sizing? - :className (stl/css :numeric-input) - :value (:height values)}]] - [:button {:class (stl/css-case - :lock-size-btn true - :selected (true? proportion-lock) - :disabled (= proportion-lock :multiple)) - :on-click on-proportion-lock-change} - (if proportion-lock - i/lock-refactor - i/unlock-refactor)]]) - (when (options :position) - [:div {:class (stl/css :position)} - [:div {:class (stl/css-case :x-position true - :disabled disabled-position-x?) - :title (tr "workspace.options.x")} - [:span {:class (stl/css :icon-text)} "X"] - [:> numeric-input* {:no-validate true - :placeholder "--" - :on-change on-pos-x-change - :disabled disabled-position-x? - :className (stl/css :numeric-input) - :value (:x values)}]] + [:& radio-buttons {:selected (or (d/name orientation) "") + :on-change on-orientation-change + :name "frame-otientation"} + [:& radio-button {:icon i/size-vertical-refactor + :value "vert" + :id "size-vertical"}] + [:& radio-button {:icon i/size-horizontal-refactor + :value "horiz" + :id "size-horizontal"}]]]) + (when (options :size) + [:div {:class (stl/css :size)} + [:div {:class (stl/css-case :width true + :disabled disabled-width-sizing?) + :title (tr "workspace.options.width")} + [:span {:class (stl/css :icon-text)} "W"] + [:> numeric-input* {:min 0.01 + :no-validate true + :placeholder "--" + :on-change on-width-change + :disabled disabled-width-sizing? + :className (stl/css :numeric-input) + :value (:width values)}]] + [:div {:class (stl/css-case :height true + :disabled disabled-height-sizing?) + :title (tr "workspace.options.height")} + [:span {:class (stl/css :icon-text)} "H"] + [:> numeric-input* {:min 0.01 + :no-validate true + :placeholder "--" + :on-change on-height-change + :disabled disabled-height-sizing? + :className (stl/css :numeric-input) + :value (:height values)}]] + [:button {:class (stl/css-case + :lock-size-btn true + :selected (true? proportion-lock) + :disabled (= proportion-lock :multiple)) + :on-click on-proportion-lock-change} + (if proportion-lock + i/lock-refactor + i/unlock-refactor)]]) + (when (options :position) + [:div {:class (stl/css :position)} + [:div {:class (stl/css-case :x-position true + :disabled disabled-position-x?) + :title (tr "workspace.options.x")} + [:span {:class (stl/css :icon-text)} "X"] + [:> numeric-input* {:no-validate true + :placeholder "--" + :on-change on-pos-x-change + :disabled disabled-position-x? + :className (stl/css :numeric-input) + :value (:x values)}]] - [:div {:class (stl/css-case :y-position true - :disabled disabled-position-y?) - :title (tr "workspace.options.y")} - [:span {:class (stl/css :icon-text)} "Y"] - [:> numeric-input* {:no-validate true - :placeholder "--" - :disabled disabled-position-y? - :on-change on-pos-y-change - :className (stl/css :numeric-input) - :value (:y values)}]]]) - (when (or (options :rotation) (options :radius)) - [:div {:class (stl/css :rotation-radius)} + [:div {:class (stl/css-case :y-position true + :disabled disabled-position-y?) + :title (tr "workspace.options.y")} + [:span {:class (stl/css :icon-text)} "Y"] + [:> numeric-input* {:no-validate true + :placeholder "--" + :disabled disabled-position-y? + :on-change on-pos-y-change + :className (stl/css :numeric-input) + :value (:y values)}]]]) + (when (or (options :rotation) (options :radius)) + [:div {:class (stl/css :rotation-radius)} - (when (options :rotation) - [:div {:class (stl/css :rotation) - :title (tr "workspace.options.rotation")} - [:span {:class (stl/css :icon)} i/rotation-refactor] - [:> numeric-input* - {:no-validate true - :min 0 - :max 359 - :data-wrap true - :placeholder "--" - :on-change on-rotation-change - :className (stl/css :numeric-input) - :value (:rotation values)}]]) - - (when (options :radius) - [:div {:class (stl/css :radius)} - [:div {:class (stl/css :radius-inputs)} - (cond - (= radius-mode :radius-1) - [:div {:class (stl/css :radius-1) - :title (tr "workspace.options.radius")} - [:span {:class (stl/css :icon)} i/corner-radius-refactor] - [:> numeric-input* - {:placeholder "Mixed" - :ref radius-input-ref - :min 0 - :on-change on-radius-1-change - :className (stl/css :numeric-input) - :value (:rx values)}]] - - @radius-multi? - [:div {:class (stl/css :radius-1) - :title (tr "workspace.options.radius")} - [:span {:class (stl/css :icon)} i/corner-radius-refactor] - [:input.input-text - {:type "number" - :placeholder "Mixed" - :min 0 - :on-change on-radius-multi-change - :className (stl/css :numeric-input) - :value (if all-equal? (:rx values) nil)}]] - - - (= radius-mode :radius-4) - [:div {:class (stl/css :radius-4)} - [:div {:class (stl/css :small-input) - :title (tr "workspace.options.radius-top-left")} - [:> numeric-input* - {:placeholder "--" - :min 0 - :on-change on-radius-r1-change - :className (stl/css :numeric-input) - :value (:r1 values)}]] - - [:div {:class (stl/css :small-input) - :title (tr "workspace.options.radius-top-right")} - [:> numeric-input* - {:placeholder "--" - :min 0 - :on-change on-radius-r2-change - :className (stl/css :numeric-input) - :value (:r2 values)}]] - - [:div {:class (stl/css :small-input) - :title (tr "workspace.options.radius-bottom-left")} - [:> numeric-input* - {:placeholder "--" - :min 0 - :on-change on-radius-r4-change - :className (stl/css :numeric-input) - :value (:r4 values)}]] - - [:div {:class (stl/css :small-input) - :title (tr "workspace.options.radius-bottom-right")} - [:> numeric-input* - {:placeholder "--" - :min 0 - :on-change on-radius-r3-change - :className (stl/css :numeric-input) - :value (:r3 values)}]] - ])] - [:button {:class (stl/css-case :radius-mode true - :selected (= radius-mode :radius-4)) - :title (if(= radius-mode :radius-4) - (tr "workspace.options.radius.all-corners") - (tr "workspace.options.radius.single-corners")) - :on-click toggle-radius-mode} - i/corner-radius-refactor]])]) - (when (or (options :clip-content) (options :show-in-viewer)) - [:div {:class (stl/css :clip-show)} - (when (options :clip-content) - [:div {:class (stl/css :clip-content)} - [:input {:type "checkbox" - :id "clip-content" - :ref clip-content-ref - :class (stl/css :clip-content-input) - :checked (not (:show-content values)) - :on-change on-change-clip-content}] - - [:label {:for "clip-content" - :title (tr "workspace.options.clip-content") - :class (stl/css-case :clip-content-label true - :selected (not (:show-content values)))} - [:span {:class (stl/css :icon)} - i/clip-content-refactor] - ]]) - (when (options :show-in-viewer) - [:div {:class (stl/css :clip-content)} - [:input {:type "checkbox" - :id "show-in-viewer" - :ref show-in-viewer-ref - :class (stl/css :clip-content-input) - :checked (not (:hide-in-viewer values)) - :on-change on-change-show-in-viewer}] - - [:label {:for "show-in-viewer" - :title (tr "workspace.options.show-in-viewer") - :class (stl/css-case :clip-content-label true - :selected (not (:hide-in-viewer values)))} - [:span {:class (stl/css :icon)} - i/play-refactor]]])])] - - [:* - [:div.element-set - [:div.element-set-content - - ;; FRAME PRESETS - (when (and (options :presets) - (or (nil? all-types) (= (count all-types) 1))) ;; Don't show presets if multi selected - [:div.row-flex ;; some frames and some non frames - [:div.presets.custom-select.flex-grow {:class (when show-presets-dropdown? "opened") - :on-click open-presets} - [:span (tr "workspace.options.size-presets")] - [:span.dropdown-button i/arrow-down] - [:& dropdown {:show show-presets-dropdown? - :on-close close-presets} - [:ul.custom-select-dropdown - (for [size-preset size-presets] - (if-not (:width size-preset) - [:li.dropdown-label {:key (:name size-preset)} - [:span (:name size-preset)]] - [:li {:key (:name size-preset) - :data-width (:width size-preset) - :data-height (:height size-preset) - :on-click on-preset-selected} - (:name size-preset) - [:span (:width size-preset) " x " (:height size-preset)]]))]]] - [:span.orientation-icon {:data-value :vert - :on-click on-orientation-clicked} i/size-vert] - [:span.orientation-icon {:data-value :horiz - :on-click on-orientation-clicked} i/size-horiz]]) - - ;; WIDTH & HEIGHT - (when (options :size) - [:div.row-flex - [:span.element-set-subtitle (tr "workspace.options.size")] - [:div.input-element.width {:title (tr "workspace.options.width")} - [:> numeric-input* {:min 0.01 - :no-validate true - :placeholder "--" - :on-change on-width-change - :disabled disabled-width-sizing? - :value (:width values)}]] - - [:div.input-element.height {:title (tr "workspace.options.height")} - [:> numeric-input* {:min 0.01 - :no-validate true - :placeholder "--" - :on-change on-height-change - :disabled disabled-height-sizing? - :value (:height values)}]] - - [:div.lock-size {:class (dom/classnames - :selected (true? proportion-lock) - :disabled (= proportion-lock :multiple)) - :on-click on-proportion-lock-change} - (if proportion-lock - i/lock - i/unlock)]]) - - ;; POSITION - (when (options :position) - [:div.row-flex - [:span.element-set-subtitle (tr "workspace.options.position")] - [:div.input-element.Xaxis {:title (tr "workspace.options.x")} - [:> numeric-input* {:no-validate true - :placeholder "--" - :on-change on-pos-x-change - :disabled disabled-position-x? - :value (:x values)}]] - [:div.input-element.Yaxis {:title (tr "workspace.options.y")} - [:> numeric-input* {:no-validate true - :placeholder "--" - :disabled disabled-position-y? - :on-change on-pos-y-change - :value (:y values)}]]]) - - ;; ROTATION - (when (options :rotation) - [:div.row-flex - [:span.element-set-subtitle (tr "workspace.options.rotation")] - [:div.input-element.degrees {:title (tr "workspace.options.rotation")} - [:> numeric-input* - {:no-validate true - :min 0 - :max 359 - :data-wrap true - :placeholder "--" - :on-change on-rotation-change - :value (:rotation values)}]]]) - - ;; RADIUS - (when (options :radius) - [:div.row-flex - [:div.radius-options - [:div.radius-icon.tooltip.tooltip-bottom - {:class (dom/classnames - :selected (or (= radius-mode :radius-1) @radius-multi?)) - :alt (tr "workspace.options.radius.all-corners") - :on-click on-switch-to-radius-1} - i/radius-1] - [:div.radius-icon.tooltip.tooltip-bottom - {:class (dom/classnames - :selected (and (= radius-mode :radius-4) (not @radius-multi?))) - :alt (tr "workspace.options.radius.single-corners") - :on-click on-switch-to-radius-4} - i/radius-4]] + (when (options :rotation) + [:div {:class (stl/css :rotation) + :title (tr "workspace.options.rotation")} + [:span {:class (stl/css :icon)} i/rotation-refactor] + [:> numeric-input* + {:no-validate true + :min 0 + :max 359 + :data-wrap true + :placeholder "--" + :on-change on-rotation-change + :className (stl/css :numeric-input) + :value (:rotation values)}]]) + (when (options :radius) + [:div {:class (stl/css :radius)} + [:div {:class (stl/css :radius-inputs)} (cond (= radius-mode :radius-1) - [:div.input-element.mini {:title (tr "workspace.options.radius")} + [:div {:class (stl/css :radius-1) + :title (tr "workspace.options.radius")} + [:span {:class (stl/css :icon)} i/corner-radius-refactor] [:> numeric-input* - {:placeholder "--" + {:placeholder "Mixed" :ref radius-input-ref :min 0 :on-change on-radius-1-change + :className (stl/css :numeric-input) :value (:rx values)}]] @radius-multi? - [:div.input-element.mini {:title (tr "workspace.options.radius")} + [:div {:class (stl/css :radius-1) + :title (tr "workspace.options.radius")} + [:span {:class (stl/css :icon)} i/corner-radius-refactor] [:input.input-text {:type "number" - :placeholder "--" + :placeholder "Mixed" :min 0 :on-change on-radius-multi-change - :value ""}]] + :className (stl/css :numeric-input) + :value (if all-equal? (:rx values) nil)}]] + (= radius-mode :radius-4) - [:* - [:div.input-element.mini {:title (tr "workspace.options.radius-top-left")} + [:div {:class (stl/css :radius-4)} + [:div {:class (stl/css :small-input) + :title (tr "workspace.options.radius-top-left")} [:> numeric-input* {:placeholder "--" :min 0 :on-change on-radius-r1-change + :className (stl/css :numeric-input) :value (:r1 values)}]] - [:div.input-element.mini {:title (tr "workspace.options.radius-top-right")} + [:div {:class (stl/css :small-input) + :title (tr "workspace.options.radius-top-right")} [:> numeric-input* {:placeholder "--" :min 0 :on-change on-radius-r2-change + :className (stl/css :numeric-input) :value (:r2 values)}]] - [:div.input-element.mini {:title (tr "workspace.options.radius-bottom-right")} - [:> numeric-input* - {:placeholder "--" - :min 0 - :on-change on-radius-r3-change - :value (:r3 values)}]] - - [:div.input-element.mini {:title (tr "workspace.options.radius-bottom-left")} + [:div {:class (stl/css :small-input) + :title (tr "workspace.options.radius-bottom-left")} [:> numeric-input* {:placeholder "--" :min 0 :on-change on-radius-r4-change - :value (:r4 values)}]]])]) - (when (options :clip-content) - [:div.input-checkbox - [:input {:type "checkbox" - :id "clip-content" - :ref clip-content-ref - :checked (not (:show-content values)) - :on-change on-change-clip-content}] + :className (stl/css :numeric-input) + :value (:r4 values)}]] - [:label {:for "clip-content"} - (tr "workspace.options.clip-content")]]) - (when (options :show-in-viewer) - [:div.input-checkbox - [:input {:type "checkbox" - :id "show-in-viewer" - :ref show-in-viewer-ref - :checked (not (:hide-in-viewer values)) - :on-change on-change-show-in-viewer}] + [:div {:class (stl/css :small-input) + :title (tr "workspace.options.radius-bottom-right")} + [:> numeric-input* + {:placeholder "--" + :min 0 + :on-change on-radius-r3-change + :className (stl/css :numeric-input) + :value (:r3 values)}]]])] + [:button {:class (stl/css-case :radius-mode true + :selected (= radius-mode :radius-4)) + :title (if (= radius-mode :radius-4) + (tr "workspace.options.radius.all-corners") + (tr "workspace.options.radius.single-corners")) + :on-click toggle-radius-mode} + i/corner-radius-refactor]])]) + (when (or (options :clip-content) (options :show-in-viewer)) + [:div {:class (stl/css :clip-show)} + (when (options :clip-content) + [:div {:class (stl/css :clip-content)} + [:input {:type "checkbox" + :id "clip-content" + :ref clip-content-ref + :class (stl/css :clip-content-input) + :checked (not (:show-content values)) + :on-change on-change-clip-content}] - [:label {:for "show-in-viewer"} - (tr "workspace.options.show-in-viewer")]])]]]))) + [:label {:for "clip-content" + :title (tr "workspace.options.clip-content") + :class (stl/css-case :clip-content-label true + :selected (not (:show-content values)))} + [:span {:class (stl/css :icon)} + i/clip-content-refactor]]]) + (when (options :show-in-viewer) + [:div {:class (stl/css :clip-content)} + [:input {:type "checkbox" + :id "show-in-viewer" + :ref show-in-viewer-ref + :class (stl/css :clip-content-input) + :checked (not (:hide-in-viewer values)) + :on-change on-change-show-in-viewer}] + + [:label {:for "show-in-viewer" + :title (tr "workspace.options.show-in-viewer") + :class (stl/css-case :clip-content-label true + :selected (not (:hide-in-viewer values)))} + [:span {:class (stl/css :icon)} + i/play-refactor]]])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss index b0a5cb1a65..f05c3e555e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss @@ -9,216 +9,235 @@ .element-set { @include flexColumn; margin-bottom: $s-8; - .presets { - display: flex; - align-items: flex-start; - gap: $s-4; - .presets-wrapper { - @extend .asset-element; - position: relative; - display: flex; - height: $s-32; - width: $s-188; - padding: $s-8; - border-radius: $br-8; - .select-name { - @include titleTipography; - display: flex; - justify-content: flex-start; - align-items: center; - flex-grow: 1; - cursor: pointer; - } - .collapsed-icon { - @include flexCenter; - cursor: pointer; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - transform: rotate(90deg); - } - } - .custom-select-dropdown { - @extend .dropdown-wrapper; - margin-top: $s-2; - width: $s-252; - .dropdown-element { - @extend .dropdown-element-base; - .name-wrapper { - display: flex; - gap: $s-8; - flex-grow: 1; - .preset-name { - color: var(--menu-foreground-color-rest); - } - .preset-size { - color: var(--menu-foreground-color-rest); - } - } +} - .check-icon { - @include flexCenter; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } +.presets { + display: flex; + align-items: flex-start; + gap: $s-4; +} - &.disabled { - pointer-events: none; - cursor: default; - .preset-name { - color: var(--menu-foreground-color); - } - } +.presets-wrapper { + @extend .asset-element; + position: relative; + display: flex; + height: $s-32; + width: $s-188; + padding: $s-8; + border-radius: $br-8; - &.match { - .name-wrapper .preset-name { - color: var(--menu-foreground-color-hover); - } - .check-icon svg { - stroke: var(--menu-foreground-color-hover); - } - } - - &:hover { - background-color: var(--menu-background-color-hover); - .name-wrapper .preset-name { - color: var(--menu-foreground-color-hover); - } - .check-icon svg { - stroke: var(--menu-foreground-color-hover); - } - } - } - } - &:hover { - .collapsed-icon svg { - stroke: var(--input-foreground-color-active); - } - } + .collapsed-icon { + @include flexCenter; + cursor: pointer; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + transform: rotate(90deg); } } - .size { - @include flexRow; - .height, - .width { - @extend .input-element; - width: $s-108; - .icon-text { - padding-top: $s-1; + + &:hover { + .collapsed-icon svg { + stroke: var(--input-foreground-color-active); + } + } +} + +.select-name { + @include titleTipography; + display: flex; + justify-content: flex-start; + align-items: center; + flex-grow: 1; + cursor: pointer; +} + +.custom-select-dropdown { + @extend .dropdown-wrapper; + margin-top: $s-2; + width: $s-252; + .dropdown-element { + @extend .dropdown-element-base; + .name-wrapper { + display: flex; + gap: $s-8; + flex-grow: 1; + .preset-name { + color: var(--menu-foreground-color-rest); } - &.disabled { - @extend .disabled-input; + .preset-size { + color: var(--menu-foreground-color-rest); } } - .lock-size-btn { - @extend .button-tertiary; - border-radius: $br-8; - height: $s-32; - width: $s-28; + + .check-icon { + @include flexCenter; svg { - @extend .button-icon; + @extend .button-icon-small; stroke: var(--icon-foreground); } - &.selected { - @extend .button-icon-selected; + } + + &.disabled { + pointer-events: none; + cursor: default; + .preset-name { + color: var(--menu-foreground-color); } } - } - .position { - @include flexRow; - .x-position, - .y-position { - @extend .input-element; - width: $s-108; - .icon-text { - padding-top: $s-1; + + &.match { + .name-wrapper .preset-name { + color: var(--menu-foreground-color-hover); } - &.disabled { - @extend .disabled-input; + .check-icon svg { + stroke: var(--menu-foreground-color-hover); } } - } - .rotation-radius { - display: flex; - align-items: flex-start; - justify-content: flex-start; - gap: $s-4; - .rotation { - @extend .input-element; - width: $s-108; - .icon-text { - padding-top: $s-1; + + &:hover { + background-color: var(--menu-background-color-hover); + .name-wrapper .preset-name { + color: var(--menu-foreground-color-hover); } - } - .radius { - display: flex; - align-items: flex-start; - justify-content: flex-start; - gap: $s-4; - .radius-inputs { - display: flex; - .radius-1 { - @extend .input-element; - width: $s-108; - } - .radius-4 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: $s-4; - .small-input { - @extend .input-element; - width: $s-52; - } - } - } - .radius-mode { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - border-radius: $br-8; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - &.selected { - background-color: var(--button-tertiary-background-color-hover); - svg { - stroke: var(--button-tertiary-foreground-color-active); - } - } - } - } - } - .clip-show { - display: flex; - align-items: flex-start; - justify-content: flex-start; - gap: $s-4; - .clip-content, - .show-in-viewer { - .clip-content-input { - display: none; - } - .clip-content-label { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - border-radius: $br-8; - .icon { - @include flexCenter; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - } - &.selected { - background-color: var(--button-tertiary-background-color-hover); - svg { - stroke: var(--button-tertiary-foreground-color-active); - } - } + .check-icon svg { + stroke: var(--menu-foreground-color-hover); + } + } + } +} + +.size { + @include flexRow; +} + +.height, +.width { + @extend .input-element; + width: $s-108; + .icon-text { + padding-top: $s-1; + } + &.disabled { + @extend .disabled-input; + } +} + +.lock-size-btn { + @extend .button-tertiary; + border-radius: $br-8; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + &.selected { + @extend .button-icon-selected; + } +} + +.position { + @include flexRow; +} + +.x-position, +.y-position { + @extend .input-element; + width: $s-108; + .icon-text { + padding-top: $s-1; + } + &.disabled { + @extend .disabled-input; + } +} + +.rotation-radius { + display: flex; + align-items: flex-start; + justify-content: flex-start; + gap: $s-4; +} + +.rotation { + @extend .input-element; + width: $s-108; + .icon-text { + padding-top: $s-1; + } +} +.radius { + display: flex; + align-items: flex-start; + justify-content: flex-start; + gap: $s-4; +} + +.radius-inputs { + display: flex; +} + +.radius-1 { + @extend .input-element; + width: $s-108; +} + +.radius-4 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: $s-4; + .small-input { + @extend .input-element; + width: $s-52; + } +} + +.radius-mode { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + border-radius: $br-8; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + &.selected { + background-color: var(--button-tertiary-background-color-hover); + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } +} + +.clip-show { + display: flex; + align-items: flex-start; + justify-content: flex-start; + gap: $s-4; +} + +.clip-content, +.show-in-viewer { + .clip-content-input { + display: none; + } + .clip-content-label { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + border-radius: $br-8; + .icon { + @include flexCenter; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + } + &.selected { + background-color: var(--button-tertiary-background-color-hover); + svg { + stroke: var(--button-tertiary-foreground-color-active); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs index a7246b2494..874e4628a5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs @@ -19,7 +19,6 @@ [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] @@ -51,8 +50,7 @@ (mf/defc shadow-entry [{:keys [ids index value on-reorder disable-drag? on-blur open-state-ref]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - basic-offset-x-ref (mf/use-ref nil) + (let [basic-offset-x-ref (mf/use-ref nil) basic-offset-y-ref (mf/use-ref nil) basic-blur-ref (mf/use-ref nil) @@ -61,9 +59,7 @@ adv-blur-ref (mf/use-ref nil) adv-spread-ref (mf/use-ref nil) - shadow-style (if new-css-system - (:style value) - (dm/str (:style value))) + shadow-style (:style value) shadow-id (:id value) @@ -143,9 +139,7 @@ (mf/use-fn (mf/deps ids index) (fn [event] - (let [value (if new-css-system - (keyword event) - (-> event dom/get-target-val d/read-string))] + (let [value (keyword event)] (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))) type-options [{:value "drop-shadow" :label (tr "workspace.options.shadow-options.drop-shadow")} @@ -155,187 +149,91 @@ manage-on-close #(st/emit! (dwu/commit-undo-transaction :color-row))] - [:div.shadow-option {:class (stl/css-case new-css-system - :global/shadow-option true - :shadow-element true - :dnd-over-top (= (:over dprops) :top) - :dnd-over-bot (= (:over dprops) :bot)) - :ref dref} - (if new-css-system - [:* - [:div {:class (stl/css :basic-options)} - [:div {:class (stl/css-case :shadow-info true - :hidden hidden?)} - [:button {:class (stl/css-case :more-options true - :selected open-shadow) - :on-click on-toggle-open-shadow} - i/menu-refactor] - [:div {:class (stl/css :type-select)} - [:& select - {:class (stl/css :shadow-type-select) - :default-value (d/name shadow-style) - :options type-options - :on-change on-type-change}]]] - [:div {:class (stl/css :actions)} - [:button {:class (stl/css :action-btn) - :on-click toggle-visibility} - (if hidden? - i/hide-refactor - i/shown-refactor)] - [:button {:class (stl/css :action-btn) - :on-click on-remove-shadow} - i/remove-refactor]]] - (when open-shadow - [:& advanced-options {:class (stl/css :shadow-advanced-options) - :visible? open-shadow - :on-close on-toggle-open-shadow} - - [:div {:class (stl/css :first-row)} - [:div {:class (stl/css :offset-x-input) - :title (tr "workspace.options.shadow-options.offsetx")} - [:span {:class (stl/css :input-label)} - "X"] - [:> numeric-input* {:className (stl/css :numeric-input) - :ref adv-offset-x-ref - :no-validate true - :placeholder "--" - :on-change (update-attr index :offset-x basic-offset-x-ref) - :on-blur on-blur - :value (:offset-x value)}]] - - [:div {:class (stl/css :blur-input) - :title (tr "workspace.options.shadow-options.blur")} - [:span {:class (stl/css :input-label)} - (tr "workspace.options.shadow-options.blur")] - [:> numeric-input* {:ref adv-blur-ref - :className (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-change (update-attr index :blur basic-blur-ref) - :on-blur on-blur - :min 0 - :value (:blur value)}]] - - [:div {:class (stl/css :spread-input) - :title (tr "workspace.options.shadow-options.spread")} - [:span {:class (stl/css :input-label)} - (tr "workspace.options.shadow-options.spread")] - [:> numeric-input* {:ref adv-spread-ref - :className (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-change (update-attr index :spread) - :on-blur on-blur - :value (:spread value)}]]] - - [:div {:class (stl/css :second-row)} - [:div {:class (stl/css :offset-y-input) - :title (tr "workspace.options.shadow-options.offsety")} - [:span {:class (stl/css :input-label)} - "Y"] - [:> numeric-input* {:ref adv-offset-y-ref - :className (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-change (update-attr index :offset-y basic-offset-y-ref) - :on-blur on-blur - :value (:offset-y value)}]] - [:& color-row {:color (if (string? (:color value)) - ;; Support for old format colors - {:color (:color value) :opacity (:opacity value)} - (:color value)) - :title (tr "workspace.options.shadow-options.color") - :disable-gradient true - :disable-image true - :on-change update-color - :on-detach detach-color - :on-open manage-on-open - :on-close manage-on-close}]]])] - - [:* - [:div.shadow-option-main {:style {:display (when open-shadow "none")}} - [:div.element-set-actions-button - {:on-click on-toggle-open-shadow} - i/actions] - - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :default-value shadow-style - :on-change on-type-change} - [:option {:value ":drop-shadow" - :selected (when (= shadow-style ":drop-shadow") "selected")} - (tr "workspace.options.shadow-options.drop-shadow")] - [:option {:value ":inner-shadow" - :selected (when (= shadow-style ":inner-shadow") "selected")} - (tr "workspace.options.shadow-options.inner-shadow")]] - - [:div.shadow-option-main-actions - [:div.element-set-actions-button {:on-click toggle-visibility} - (if hidden? i/eye-closed i/eye)] - [:div.element-set-actions-button - {:data-index index - :on-click on-remove-shadow} - i/minus]]] - - [:& advanced-options {:visible? open-shadow + [:div {:class (stl/css-case :global/shadow-option true + :shadow-element true + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref} + [:* + [:div {:class (stl/css :basic-options)} + [:div {:class (stl/css-case :shadow-info true + :hidden hidden?)} + [:button {:class (stl/css-case :more-options true + :selected open-shadow) + :on-click on-toggle-open-shadow} + i/menu-refactor] + [:div {:class (stl/css :type-select)} + [:& select + {:class (stl/css :shadow-type-select) + :default-value (d/name shadow-style) + :options type-options + :on-change on-type-change}]]] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click toggle-visibility} + (if hidden? + i/hide-refactor + i/shown-refactor)] + [:button {:class (stl/css :action-btn) + :on-click on-remove-shadow} + i/remove-refactor]]] + (when open-shadow + [:& advanced-options {:class (stl/css :shadow-advanced-options) + :visible? open-shadow :on-close on-toggle-open-shadow} - [:div.color-data - [:div.element-set-actions-button - {:on-click on-toggle-open-shadow} - i/actions] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :default-value shadow-style - :on-change on-type-change} - [:option {:value ":drop-shadow" - :selected (when (= shadow-style ":drop-shadow") "selected")} - (tr "workspace.options.shadow-options.drop-shadow")] - [:option {:value ":inner-shadow" - :selected (when (= shadow-style ":inner-shadow") "selected")} - (tr "workspace.options.shadow-options.inner-shadow")]]] - [:div.row-grid-2 - [:div.input-element {:title (tr "workspace.options.shadow-options.offsetx")} - [:> numeric-input* {:ref adv-offset-x-ref + [:div {:class (stl/css :first-row)} + [:div {:class (stl/css :offset-x-input) + :title (tr "workspace.options.shadow-options.offsetx")} + [:span {:class (stl/css :input-label)} + "X"] + [:> numeric-input* {:className (stl/css :numeric-input) + :ref adv-offset-x-ref :no-validate true :placeholder "--" :on-change (update-attr index :offset-x basic-offset-x-ref) :on-blur on-blur - :value (:offset-x value)}] - [:span.after (tr "workspace.options.shadow-options.offsetx")]] + :value (:offset-x value)}]] - [:div.input-element {:title (tr "workspace.options.shadow-options.offsety")} - [:> numeric-input* {:ref adv-offset-y-ref - :no-validate true - :placeholder "--" - :on-change (update-attr index :offset-y basic-offset-y-ref) - :on-blur on-blur - :value (:offset-y value)}] - [:span.after (tr "workspace.options.shadow-options.offsety")]]] - - [:div.row-grid-2 - [:div.input-element {:title (tr "workspace.options.shadow-options.blur")} + [:div {:class (stl/css :blur-input) + :title (tr "workspace.options.shadow-options.blur")} + [:span {:class (stl/css :input-label)} + (tr "workspace.options.shadow-options.blur")] [:> numeric-input* {:ref adv-blur-ref + :className (stl/css :numeric-input) :no-validate true :placeholder "--" :on-change (update-attr index :blur basic-blur-ref) :on-blur on-blur :min 0 - :value (:blur value)}] - [:span.after (tr "workspace.options.shadow-options.blur")]] + :value (:blur value)}]] - [:div.input-element {:title (tr "workspace.options.shadow-options.spread")} + [:div {:class (stl/css :spread-input) + :title (tr "workspace.options.shadow-options.spread")} + [:span {:class (stl/css :input-label)} + (tr "workspace.options.shadow-options.spread")] [:> numeric-input* {:ref adv-spread-ref + :className (stl/css :numeric-input) :no-validate true :placeholder "--" :on-change (update-attr index :spread) :on-blur on-blur - :value (:spread value)}] - [:span.after (tr "workspace.options.shadow-options.spread")]]] + :value (:spread value)}]]] - [:div.color-row-wrap + [:div {:class (stl/css :second-row)} + [:div {:class (stl/css :offset-y-input) + :title (tr "workspace.options.shadow-options.offsety")} + [:span {:class (stl/css :input-label)} + "Y"] + [:> numeric-input* {:ref adv-offset-y-ref + :className (stl/css :numeric-input) + :no-validate true + :placeholder "--" + :on-change (update-attr index :offset-y basic-offset-y-ref) + :on-blur on-blur + :value (:offset-y value)}]] [:& color-row {:color (if (string? (:color value)) - ;; Support for old format colors + ;; Support for old format colors {:color (:color value) :opacity (:opacity value)} (:color value)) :title (tr "workspace.options.shadow-options.color") @@ -344,13 +242,12 @@ :on-change update-color :on-detach detach-color :on-open manage-on-open - :on-close manage-on-close}]]]])])) + :on-close manage-on-close}]]])]])) (mf/defc shadow-menu {::mf/wrap-props false} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - ids (unchecked-get props "ids") + (let [ids (unchecked-get props "ids") type (unchecked-get props "type") values (unchecked-get props "values") @@ -389,70 +286,35 @@ (mf/deps ids) #(st/emit! (dc/add-shadow ids (create-shadow))))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-shadows? - :collapsed? (not open?) - :on-collapsed toggle-content - :title (case type - :multiple (tr "workspace.options.shadow-options.title.multiple") - :group (tr "workspace.options.shadow-options.title.group") - (tr "workspace.options.shadow-options.title")) - :class (stl/css-case :title-spacing-shadow (not has-shadows?))} + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-shadows? + :collapsed? (not open?) + :on-collapsed toggle-content + :title (case type + :multiple (tr "workspace.options.shadow-options.title.multiple") + :group (tr "workspace.options.shadow-options.title.group") + (tr "workspace.options.shadow-options.title")) + :class (stl/css-case :title-spacing-shadow (not has-shadows?))} - (when-not (= :multiple shadows) - [:button {:class (stl/css :add-shadow) - :on-click on-add-shadow} i/add-refactor])]] - - (when open? - (cond - (= :multiple shadows) - [:div {:class (stl/css :element-set-content)} - [:div {:class (stl/css :multiple-shadows)} - [:div {:class (stl/css :label)} (tr "settings.multiple")] - [:div {:class (stl/css :actions)} - [:button {:class (stl/css :action-btn) - :on-click on-remove-all} - i/remove-refactor]]]] - - (seq shadows) - [:& h/sortable-container {} - [:div {:class (stl/css :element-set-content)} - (for [[index value] (d/enumerate shadows)] - [:& shadow-entry - {:key (dm/str "shadow-" index) - :ids ids - :value value - :on-reorder handle-reorder - :disable-drag? disable-drag? - :on-blur on-blur - :index index - :open-state-ref open-state-ref}])]]))] - - [:div.element-set.shadow-options - [:div.element-set-title - [:span - (case type - :multiple (tr "workspace.options.shadow-options.title.multiple") - :group (tr "workspace.options.shadow-options.title.group") - (tr "workspace.options.shadow-options.title"))] - - (when-not (= :multiple shadows) - [:div.add-page {:on-click on-add-shadow} i/close])] + (when-not (= :multiple shadows) + [:button {:class (stl/css :add-shadow) + :on-click on-add-shadow} i/add-refactor])]] + (when open? (cond (= :multiple shadows) - [:div.element-set-content - [:div.element-set-options-group - [:div.element-set-label (tr "settings.multiple")] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click on-remove-all} - i/minus]]]] + [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :multiple-shadows)} + [:div {:class (stl/css :label)} (tr "settings.multiple")] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click on-remove-all} + i/remove-refactor]]]] (seq shadows) [:& h/sortable-container {} - [:div.element-set-content + [:div {:class (stl/css :element-set-content)} (for [[index value] (d/enumerate shadows)] [:& shadow-entry {:key (dm/str "shadow-" index) @@ -462,4 +324,4 @@ :disable-drag? disable-drag? :on-blur on-blur :index index - :open-state-ref open-state-ref}])]])]))) + :open-state-ref open-state-ref}])]]))])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss index e5c27782a3..a9ef8ebd20 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss @@ -8,129 +8,127 @@ .element-set { margin: 0; - .element-title { - .title-spacing-shadow { - margin: 0; - padding-left: $s-2; +} + +.title-spacing-shadow { + margin: 0; + padding-left: $s-2; +} +.add-shadow { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.element-set-content { + margin-top: $s-4; + @include flexColumn; +} + +.multiple-shadows { + @include flexRow; +} + +.label { + @extend .mixed-bar; +} + +.actions { + @include flexRow; +} + +.action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.shadow-element { + @include flexColumn; +} + +.basic-options { + @include flexRow; +} + +.shadow-info { + display: flex; + align-items: center; + gap: $s-1; + width: $s-188; + .more-options { + @extend .button-secondary; + height: $s-32; + width: $s-28; + border-radius: $br-8 0 0 $br-8; + svg { + @extend .button-icon; } - .add-shadow { - @extend .button-tertiary; - height: $s-32; - width: $s-28; + &.selected { + background-color: var(--button-radio-background-color-active); svg { - @extend .button-icon; + stroke: var(--button-radio-foreground-color-active); } } } - .element-set-content { - margin-top: $s-4; - @include flexColumn; - .multiple-shadows { - @include flexRow; - .label { - @extend .mixed-bar; - } - .actions { - @include flexRow; - .action-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } + .type-select { + padding: 0; + border-radius: 0 $br-8 $br-8 0; + flex-grow: 1; + .shadow-type-select { + flex-grow: 1; + border-radius: 0 $br-8 $br-8 0; } - .shadow-element { - @include flexColumn; - .basic-options { - @include flexRow; - .shadow-info { - display: flex; - align-items: center; - gap: $s-1; - width: $s-188; - .more-options { - @extend .button-secondary; - height: $s-32; - width: $s-28; - border-radius: $br-8 0 0 $br-8; - svg { - @extend .button-icon; - } - &.selected { - background-color: var(--button-radio-background-color-active); - svg { - stroke: var(--button-radio-foreground-color-active); - } - } - } - .type-select { - padding: 0; - border-radius: 0 $br-8 $br-8 0; - flex-grow: 1; - .shadow-type-select { - flex-grow: 1; - border-radius: 0 $br-8 $br-8 0; - } - } + } - &.hidden { - .more-options { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - } - .type-select { - @include hiddenElement; - .shadow-type-select { - @include hiddenElement; - border: $s-1 solid var(--input-border-color-disabled); - } - } - } - } - .actions { - @include flexRow; - .action-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - } - .shadow-advanced-options { - @include flexColumn; - .first-row, - .second-row { - @include flexRow; - .offset-x-input, - .blur-input, - .spread-input, - .offset-y-input { - @extend .input-element; - width: $s-60; - min-width: $s-60; - align-items: baseline; - input { - width: $s-32; - } - } - .blur-input, - .spread-input { - width: $s-92; - .input-label { - width: $s-44; - } - } - .spread-input { - gap: $s-8; - } - } + &.hidden { + .more-options { + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); + } + .type-select { + @include hiddenElement; + .shadow-type-select { + @include hiddenElement; + border: $s-1 solid var(--input-border-color-disabled); } } } } + +.shadow-advanced-options { + @include flexColumn; +} + +.first-row, +.second-row { + @include flexRow; + .offset-x-input, + .blur-input, + .spread-input, + .offset-y-input { + @extend .input-element; + width: $s-60; + min-width: $s-60; + align-items: baseline; + input { + width: $s-32; + } + } + .blur-input, + .spread-input { + width: $s-92; + .input-label { + width: $s-44; + } + } + .spread-input { + gap: $s-8; + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs index 90d4d9ac33..093434da9b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs @@ -13,7 +13,6 @@ [app.main.data.workspace.colors :as dc] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.stroke-row :refer [stroke-row]] @@ -38,8 +37,7 @@ (mf/defc stroke-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "show-caps"]))]} [{:keys [ids type values show-caps disable-stroke-style] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - label (case type + (let [label (case type :multiple (tr "workspace.options.selection-stroke") :group (tr "workspace.options.group-stroke") (tr "workspace.options.stroke")) @@ -53,27 +51,15 @@ strokes (:strokes values) has-strokes? (or (= :multiple strokes) (some? (seq strokes))) - handle-change-stroke-color - (mf/use-fn - (mf/deps ids) - (fn [index] - (fn [color] - (st/emit! (dc/change-stroke ids color index))))) - on-color-change-refactor + on-color-change (mf/use-fn (mf/deps ids) (fn [index color] (st/emit! (dc/change-stroke ids color index)))) - handle-remove - (mf/use-fn - (mf/deps ids) - (fn [index] - (fn [] - (st/emit! (dc/remove-stroke ids index))))) - on-remove-refactor + on-remove (mf/use-fn (mf/deps ids) (fn [index] @@ -85,16 +71,7 @@ (fn [_] (st/emit! (dc/remove-all-strokes ids)))) - handle-detach - (mf/use-fn - (mf/deps ids) - (fn [index] - (fn [color] - (let [color (-> color - (assoc :id nil :file-id nil))] - (st/emit! (dc/change-stroke ids color index)))))) - - on-color-detach-refactor + on-color-detach (mf/use-fn (mf/deps ids) (fn [index color] @@ -110,42 +87,19 @@ (st/emit! (dc/reorder-strokes ids index new-index))))) on-stroke-style-change - (fn [index] - (fn [event] - (let [value (-> (dom/get-target event) - (dom/get-value) - (d/read-string))] - (st/emit! (dc/change-stroke ids {:stroke-style value} index))))) - - on-stroke-style-change-refactor (mf/use-fn (mf/deps ids) (fn [index value] (st/emit! (dc/change-stroke ids {:stroke-style value} index)))) - on-stroke-alignment-change - (fn [index] - (fn [event] - (let [value (-> (dom/get-target event) - (dom/get-value) - (d/read-string))] - (when-not (str/empty? value) - (st/emit! (dc/change-stroke ids {:stroke-alignment value} index)))))) - - on-stroke-alignment-change-refactor (fn [index value] (when-not (str/empty? value) (st/emit! (dc/change-stroke ids {:stroke-alignment value} index)))) - on-stroke-width-change - (fn [index] - (fn [value] - (when-not (str/empty? value) - (st/emit! (dc/change-stroke ids {:stroke-width value} index))))) - on-stroke-width-change-refactor + on-stroke-width-change (fn [index value] (when-not (str/empty? value) (st/emit! (dc/change-stroke ids {:stroke-width value} index)))) @@ -207,70 +161,27 @@ on-blur (fn [_] (reset! disable-drag false))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? has-strokes? - :collapsed? (not open?) - :on-collapsed toggle-content - :title label - :class (stl/css-case :title-spacing-stroke (not has-strokes?))} + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? has-strokes? + :collapsed? (not open?) + :on-collapsed toggle-content + :title label + :class (stl/css-case :title-spacing-stroke (not has-strokes?))} - [:button {:class (stl/css :add-stroke) - :on-click on-add-stroke} i/add-refactor]]] - (when open? - [:div {:class (stl/css-case :element-content true - :empty-content (not has-strokes?))} - (cond - (= :multiple strokes) - [:div {:class (stl/css :element-set-options-group)} - [:div {:class (stl/css :group-label)} - (tr "settings.multiple")] - [:button {:on-click handle-remove-all - :class (stl/css :remove-btn)} - i/remove-refactor]] - (seq strokes) - [:& h/sortable-container {} - (for [[index value] (d/enumerate (:strokes values []))] - [:& stroke-row {:key (dm/str "stroke-" index) - :stroke value - :title (tr "workspace.options.stroke-color") - :index index - :show-caps show-caps - :on-color-change on-color-change-refactor - :on-color-detach on-color-detach-refactor - :on-stroke-width-change on-stroke-width-change-refactor - :on-stroke-style-change on-stroke-style-change-refactor - :on-stroke-alignment-change on-stroke-alignment-change-refactor - :open-caps-select open-caps-select - :close-caps-select close-caps-select - :on-stroke-cap-start-change on-stroke-cap-start-change - :on-stroke-cap-end-change on-stroke-cap-end-change - :on-stroke-cap-switch on-stroke-cap-switch - :on-remove on-remove-refactor - :on-reorder (handle-reorder index) - :disable-drag disable-drag - :on-focus on-focus - :select-on-focus (not @disable-drag) - :on-blur on-blur - :disable-stroke-style disable-stroke-style}])])])] - - - [:div.element-set - [:div.element-set-title - [:span label] - [:div.add-page {:on-click on-add-stroke} i/close]] - - [:div.element-set-content + [:button {:class (stl/css :add-stroke) + :on-click on-add-stroke} i/add-refactor]]] + (when open? + [:div {:class (stl/css-case :element-content true + :empty-content (not has-strokes?))} (cond (= :multiple strokes) - [:div.element-set-options-group - [:div.element-set-label (tr "settings.multiple")] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click handle-remove-all} - i/minus]]] - - + [:div {:class (stl/css :element-set-options-group)} + [:div {:class (stl/css :group-label)} + (tr "settings.multiple")] + [:button {:on-click handle-remove-all + :class (stl/css :remove-btn)} + i/remove-refactor]] (seq strokes) [:& h/sortable-container {} (for [[index value] (d/enumerate (:strokes values []))] @@ -279,8 +190,8 @@ :title (tr "workspace.options.stroke-color") :index index :show-caps show-caps - :on-color-change handle-change-stroke-color - :on-color-detach handle-detach + :on-color-change on-color-change + :on-color-detach on-color-detach :on-stroke-width-change on-stroke-width-change :on-stroke-style-change on-stroke-style-change :on-stroke-alignment-change on-stroke-alignment-change @@ -289,10 +200,10 @@ :on-stroke-cap-start-change on-stroke-cap-start-change :on-stroke-cap-end-change on-stroke-cap-end-change :on-stroke-cap-switch on-stroke-cap-switch - :on-remove handle-remove + :on-remove on-remove :on-reorder (handle-reorder index) :disable-drag disable-drag :on-focus on-focus :select-on-focus (not @disable-drag) :on-blur on-blur - :disable-stroke-style disable-stroke-style}])])]]))) + :disable-stroke-style disable-stroke-style}])])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss index 252334692e..53f6af64e0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss @@ -8,43 +8,48 @@ .element-set { margin: 0; - .element-title { - margin: 0; - .title-spacing-stroke { - padding-left: $s-2; - margin: 0; - } - .add-stroke { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } +} - .element-content { - display: flex; - flex-direction: column; - gap: $s-12; - margin: $s-4 0 $s-8 0; - .element-set-options-group { - @include flexRow; - .group-label { - @extend .mixed-bar; - } - .remove-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - &.empty-content { - margin: 0; - } +.element-title { + margin: 0; +} + +.title-spacing-stroke { + padding-left: $s-2; + margin: 0; +} +.add-stroke { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.element-content { + display: flex; + flex-direction: column; + gap: $s-12; + margin: $s-4 0 $s-8 0; + &.empty-content { + margin: 0; + } +} + +.element-set-options-group { + @include flexRow; +} + +.group-label { + @extend .mixed-bar; +} + +.remove-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs index 792b83f943..2092e55101 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs @@ -11,16 +11,13 @@ [app.main.data.workspace.changes :as dch] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [rumext.v2 :as mf])) (mf/defc attribute-value [{:keys [attr value on-change on-delete] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - handle-change + (let [handle-change (mf/use-fn (mf/deps attr on-change) (fn [event] @@ -33,56 +30,31 @@ (on-delete attr))) label (->> attr last d/name)] - (if new-css-system - [:* - (if (string? value) - [:div {:class (stl/css :attr-content)} - [:span {:class (stl/css :attr-name)} label] - [:div {:class (stl/css :attr-input)} - [:input {:value value - :class "input-text" - :on-change handle-change}]] - [:div {:class (stl/css :attr-actions)} - [:button {:class (stl/css :attr-action-btn) - :on-click handle-delete} - i/remove-refactor]]] - [:div {:class (stl/css :attr-nested-content)} - [:div {:class (stl/css :attr-title)} - (str (d/name (last attr)))] - (for [[key value] value] - [:div {:class (stl/css :attr-row) :key key} - [:& attribute-value {:key key - :attr (conj attr key) - :value value - :on-change on-change - :on-delete on-delete}]])])] - [:div.element-set-content - (if (string? value) - [:div.row-flex.row-flex-removable - [:& input-row {:label label - :type :text - :class "large" - :value (str value) - :on-change handle-change}] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click handle-delete} - i/minus]]] - - [:* - [:div.element-set-title - {:style {:border-bottom "1px solid #444" :margin-bottom "0.5rem"}} - [:span (str (d/name (last attr)))]] - - (for [[key value] value] - [:& attribute-value {:key key - :attr (conj attr key) - :value value - :on-change on-change - :on-delete on-delete}])])]))) + [:* + (if (string? value) + [:div {:class (stl/css :attr-content)} + [:span {:class (stl/css :attr-name)} label] + [:div {:class (stl/css :attr-input)} + [:input {:value value + :class "input-text" + :on-change handle-change}]] + [:div {:class (stl/css :attr-actions)} + [:button {:class (stl/css :attr-action-btn) + :on-click handle-delete} + i/remove-refactor]]] + [:div {:class (stl/css :attr-nested-content)} + [:div {:class (stl/css :attr-title)} + (str (d/name (last attr)))] + (for [[key value] value] + [:div {:class (stl/css :attr-row) :key key} + [:& attribute-value {:key key + :attr (conj attr key) + :value value + :on-change on-change + :on-delete on-delete}]])])])) (mf/defc svg-attrs-menu [{:keys [ids values]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - state* (mf/use-state true) + (let [state* (mf/use-state true) open? (deref state*) attrs (:svg-attrs values) has-attributes? (or (= :multiple attrs) (some? (seq attrs))) @@ -112,30 +84,18 @@ (st/emit! (dch/update-shapes ids update-fn)))))] (when-not (empty? attrs) - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-set-title)} - [:& title-bar {:collapsable? has-attributes? - :collapsed? (not open?) - :on-collapsed toggle-content - :title (tr "workspace.sidebar.options.svg-attrs.title") - :class (stl/css-case :title-spacing-svg-attrs (not has-attributes?))}]] - (when open? - [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-set-title)} + [:& title-bar {:collapsable? has-attributes? + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.sidebar.options.svg-attrs.title") + :class (stl/css-case :title-spacing-svg-attrs (not has-attributes?))}]] + (when open? + [:div {:class (stl/css :element-set-content)} (for [[attr-key attr-value] attrs] [:& attribute-value {:key attr-key :attr [attr-key] :value attr-value :on-change handle-change - :on-delete handle-delete}])])] - - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.sidebar.options.svg-attrs.title")]] - - (for [[attr-key attr-value] attrs] - [:& attribute-value {:key attr-key - :attr [attr-key] - :value attr-value - :on-change handle-change - :on-delete handle-delete}])])))) + :on-delete handle-delete}])])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss index 5926c782b8..536f589c99 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss @@ -8,41 +8,49 @@ .element-set { margin: 0; - .title-spacing-svg-attrs { - padding-left: $s-2; - margin: 0; - } - .element-set-content { - @include flexColumn; - margin: $s-4 0 0 0; - .attr-content { - display: flex; - gap: $s-4; - .attr-name { - @include titleTipography; - @include twoLineTextEllipsis; - width: $s-88; - margin: auto $s-4; - margin-right: 0; - display: inline-block; - } - .attr-input { - @extend .input-element; - width: $s-124; - } - .attr-actions { - display: flex; - gap: $s-4; - .attr-action-btn { - @extend .button-tertiary; - width: $s-28; - height: $s-32; - svg { - @extend .button-icon; - } - } - } - } +} + +.title-spacing-svg-attrs { + padding-left: $s-2; + margin: 0; +} + +.element-set-content { + @include flexColumn; + margin: $s-4 0 0 0; +} + +.attr-content { + display: flex; + gap: $s-4; +} + +.attr-name { + @include titleTipography; + @include twoLineTextEllipsis; + width: $s-88; + margin: auto $s-4; + margin-right: 0; + display: inline-block; + color: var(--title-foreground-color); +} + +.attr-input { + @extend .input-element; + width: $s-124; +} + +.attr-actions { + display: flex; + gap: $s-4; +} + +.attr-action-btn { + @extend .button-tertiary; + width: $s-28; + height: $s-32; + svg { + @extend .button-icon; } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs index 8e393ae2de..913630f049 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs @@ -30,181 +30,101 @@ (mf/defc text-align-options [{:keys [values on-change on-blur] :as props}] (let [{:keys [text-align]} values - new-css-system (mf/use-ctx ctx/new-css-system) - handle-change (mf/use-fn + (mf/deps on-blur) (fn [value] - (let [new-align (if new-css-system - value - (-> (dom/get-current-target value) - (dom/get-data "value")))] - (on-change {:text-align new-align}) - (when (some? on-blur) (on-blur)))))] + (on-change {:text-align value}) + (when (some? on-blur) (on-blur))))] ;; --- Align - (if new-css-system - [:div {:class (stl/css :align-options)} - [:& radio-buttons {:selected text-align - :on-change handle-change - :name "align-text-options"} - [:& radio-button {:value "left" - :id "text-align-left" - :title (tr "workspace.options.text-options.text-align-left" (sc/get-tooltip :text-align-left)) - :icon i/text-align-left-refactor}] - [:& radio-button {:value "center" - :id "text-align-center" - :title (tr "workspace.options.text-options.text-align-center" (sc/get-tooltip :text-align-center)) - :icon i/text-align-center-refactor}] - [:& radio-button {:value "right" - :id "text-align-right" - :title (tr "workspace.options.text-options.text-align-right" (sc/get-tooltip :text-align-right)) - :icon i/text-align-right-refactor}] - [:& radio-button {:value "justify" - :id "text-align-justify" - :title (tr "workspace.options.text-options.text-align-justify" (sc/get-tooltip :text-align-justify)) - :icon i/text-justify-refactor}]]] - [:div.align-icons - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-left" (sc/get-tooltip :text-align-left)) - :class (dom/classnames :current (= "left" text-align)) - :data-value "left" - :on-click handle-change} - i/text-align-left] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-center" (sc/get-tooltip :text-align-center)) - :class (dom/classnames :current (= "center" text-align)) - :data-value "center" - :on-click handle-change} - i/text-align-center] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-right" (sc/get-tooltip :text-align-right)) - :class (dom/classnames :current (= "right" text-align)) - :data-value "right" - :on-click handle-change} - i/text-align-right] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-justify" (sc/get-tooltip :text-align-justify)) - :class (dom/classnames :current (= "justify" text-align)) - :data-value "justify" - :on-click handle-change} - i/text-align-justify]]))) + [:div {:class (stl/css :align-options)} + [:& radio-buttons {:selected text-align + :on-change handle-change + :name "align-text-options"} + [:& radio-button {:value "left" + :id "text-align-left" + :title (tr "workspace.options.text-options.text-align-left" (sc/get-tooltip :text-align-left)) + :icon i/text-align-left-refactor}] + [:& radio-button {:value "center" + :id "text-align-center" + :title (tr "workspace.options.text-options.text-align-center" (sc/get-tooltip :text-align-center)) + :icon i/text-align-center-refactor}] + [:& radio-button {:value "right" + :id "text-align-right" + :title (tr "workspace.options.text-options.text-align-right" (sc/get-tooltip :text-align-right)) + :icon i/text-align-right-refactor}] + [:& radio-button {:value "justify" + :id "text-align-justify" + :title (tr "workspace.options.text-options.text-align-justify" (sc/get-tooltip :text-align-justify)) + :icon i/text-justify-refactor}]]])) (mf/defc text-direction-options [{:keys [values on-change on-blur] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - direction (:text-direction values) + (let [direction (:text-direction values) handle-change (mf/use-fn (mf/deps direction) (fn [value] - (let [val (if new-css-system - value - (-> (dom/get-current-target value) - (dom/get-data "value"))) - dir (if (= val direction) + (let [dir (if (= value direction) "none" - val)] + value)] (on-change {:text-direction dir}) (when (some? on-blur) (on-blur)))))] - (if new-css-system - [:div {:class (stl/css :text-direction-options)} - [:& radio-buttons {:selected direction - :on-change handle-change - :name "text-direction-options"} - [:& radio-button {:value "ltr" - :type "checkbox" - :id "ltr-text-direction" - :title (tr "workspace.options.text-options.direction-ltr") - :icon i/text-ltr-refactor}] - [:& radio-button {:value "rtl" - :type "checkbox" - :id "rtl-text-direction" - :title (tr "workspace.options.text-options.direction-rtl") - :icon i/text-rtl-refactor}]]] - ;; --- Align - [:div.align-icons - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.direction-ltr") - :class (dom/classnames :current (= "ltr" direction)) - :data-value "ltr" - :on-click handle-change} - i/text-direction-ltr] - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.direction-rtl") - :class (dom/classnames :current (= "rtl" direction)) - :data-value "rtl" - :on-click handle-change} - i/text-direction-rtl]]))) + [:div {:class (stl/css :text-direction-options)} + [:& radio-buttons {:selected direction + :on-change handle-change + :name "text-direction-options"} + [:& radio-button {:value "ltr" + :type "checkbox" + :id "ltr-text-direction" + :title (tr "workspace.options.text-options.direction-ltr") + :icon i/text-ltr-refactor}] + [:& radio-button {:value "rtl" + :type "checkbox" + :id "rtl-text-direction" + :title (tr "workspace.options.text-options.direction-rtl") + :icon i/text-rtl-refactor}]]])) (mf/defc vertical-align [{:keys [values on-change on-blur] :as props}] (let [{:keys [vertical-align]} values - new-css-system (mf/use-ctx ctx/new-css-system) vertical-align (or vertical-align "top") handle-change (mf/use-fn + (mf/deps on-blur) (fn [value] - (let [new-align (if new-css-system - value - (-> (dom/get-current-target value) - (dom/get-data "value")))] - (on-change {:vertical-align new-align}) - (when (some? on-blur) (on-blur)))))] + (on-change {:vertical-align value}) + (when (some? on-blur) (on-blur))))] - (if new-css-system - [:div {:class (stl/css :vertical-align-options)} - [:& radio-buttons {:selected vertical-align - :on-change handle-change - :name "vertical-align-text-options"} - [:& radio-button {:value "top" - :id "vertical-text-align-top" - :title (tr "workspace.options.text-options.align-top") - :icon i/text-top-refactor}] - [:& radio-button {:value "center" - :id "vertical-text-align-center" - :title (tr "workspace.options.text-options.align-middle") - :icon i/text-middle-refactor}] - [:& radio-button {:value "bottom" - :id "vertical-text-align-bottom" - :title (tr "workspace.options.text-options.align-bottom") - :icon i/text-bottom-refactor}]]] - [:div.align-icons - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.align-top") - :class (dom/classnames :current (= "top" vertical-align)) - :data-value "top" - :on-click handle-change} - i/align-top] - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.align-middle") - :class (dom/classnames :current (= "center" vertical-align)) - :data-value "center" - :on-click handle-change} - i/align-middle] - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.align-bottom") - :class (dom/classnames :current (= "bottom" vertical-align)) - :data-value "bottom" - :on-click handle-change} - i/align-bottom]]))) + [:div {:class (stl/css :vertical-align-options)} + [:& radio-buttons {:selected vertical-align + :on-change handle-change + :name "vertical-align-text-options"} + [:& radio-button {:value "top" + :id "vertical-text-align-top" + :title (tr "workspace.options.text-options.align-top") + :icon i/text-top-refactor}] + [:& radio-button {:value "center" + :id "vertical-text-align-center" + :title (tr "workspace.options.text-options.align-middle") + :icon i/text-middle-refactor}] + [:& radio-button {:value "bottom" + :id "vertical-text-align-bottom" + :title (tr "workspace.options.text-options.align-bottom") + :icon i/text-bottom-refactor}]]])) (mf/defc grow-options [{:keys [ids values on-blur] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - grow-type (:grow-type values) + (let [grow-type (:grow-type values) handle-change-grow (mf/use-fn - (mf/deps ids new-css-system) + (mf/deps ids on-blur) (fn [value] (let [uid (js/Symbol) - grow-type (if new-css-system - (keyword value) - (-> (dom/get-current-target value) - (dom/get-data "value") - (keyword)))] + grow-type (keyword value)] (st/emit! (dwu/start-undo-transaction uid) (dch/update-shapes ids #(assoc % :grow-type grow-type))) @@ -212,105 +132,55 @@ (ts/schedule #(st/emit! (dwu/commit-undo-transaction uid)))) (when (some? on-blur) (on-blur))))] - (if new-css-system - [:div {:class (stl/css :grow-options)} - [:& radio-buttons {:selected (d/name grow-type) - :on-change handle-change-grow - :name "grow-text-options"} - [:& radio-button {:value "fixed" - :id "text-fixed-grow" - :title (tr "workspace.options.text-options.grow-fixed") - :icon i/text-fixed-refactor}] - [:& radio-button {:value "auto-width" - :id "text-auto-width-grow" - :title (tr "workspace.options.text-options.grow-auto-width") - :icon i/text-auto-width-refactor}] - [:& radio-button {:value "auto-height" - :id "text-auto-height-grow" - :title (tr "workspace.options.text-options.grow-auto-height") - :icon i/text-auto-height-refactor}]]] - - [:div.align-icons - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.grow-fixed") - :class (dom/classnames :current (= :fixed grow-type)) - :data-value "fixed" - :on-click handle-change-grow} - i/auto-fix] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.grow-auto-width") - :data-value "auto-width" - :class (dom/classnames :current (= :auto-width grow-type)) - :on-click handle-change-grow} - i/auto-width] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.grow-auto-height") - :class (dom/classnames :current (= :auto-height grow-type)) - :data-value "auto-height" - :on-click handle-change-grow} - i/auto-height]]))) + [:div {:class (stl/css :grow-options)} + [:& radio-buttons {:selected (d/name grow-type) + :on-change handle-change-grow + :name "grow-text-options"} + [:& radio-button {:value "fixed" + :id "text-fixed-grow" + :title (tr "workspace.options.text-options.grow-fixed") + :icon i/text-fixed-refactor}] + [:& radio-button {:value "auto-width" + :id "text-auto-width-grow" + :title (tr "workspace.options.text-options.grow-auto-width") + :icon i/text-auto-width-refactor}] + [:& radio-button {:value "auto-height" + :id "text-auto-height-grow" + :title (tr "workspace.options.text-options.grow-auto-height") + :icon i/text-auto-height-refactor}]]])) (mf/defc text-decoration-options [{:keys [values on-change on-blur] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - text-decoration (or (:text-decoration values) "none") + (let [text-decoration (or (:text-decoration values) "none") handle-change (mf/use-fn (mf/deps text-decoration) (fn [value] - (let [val (if new-css-system - value - (-> (dom/get-current-target value) - (dom/get-data "value"))) - decoration (if (= val text-decoration) + (let [decoration (if (= value text-decoration) "none" - val)] + value)] (on-change {:text-decoration decoration}) (when (some? on-blur) (on-blur)))))] - (if new-css-system - [:div {:class (stl/css :text-decoration-options)} - [:& radio-buttons {:selected text-decoration - :on-change handle-change - :name "text-decoration-options"} - [:& radio-button {:value "underline" - :type "checkbox" - :id "underline-text-decoration" - :title (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) - :icon i/text-underlined-refactor}] - [:& radio-button {:value "line-through" - :type "checkbox" - :id "line-through-text-decoration" - :title (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) - :icon i/text-stroked-refactor}]]] - - [:div.align-icons - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.none") - :class (dom/classnames :current (= "none" text-decoration)) - :data-value "none" - :on-click handle-change} - i/minus] - - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) - :class (dom/classnames :current (= "underline" text-decoration)) - :data-value "underline" - :on-click handle-change} - i/underline] - - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) - :class (dom/classnames :current (= "line-through" text-decoration)) - :data-value "line-through" - :on-click handle-change} - i/strikethrough]]))) + [:div {:class (stl/css :text-decoration-options)} + [:& radio-buttons {:selected text-decoration + :on-change handle-change + :name "text-decoration-options"} + [:& radio-button {:value "underline" + :type "checkbox" + :id "underline-text-decoration" + :title (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) + :icon i/text-underlined-refactor}] + [:& radio-button {:value "line-through" + :type "checkbox" + :id "line-through-text-decoration" + :title (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) + :icon i/text-stroked-refactor}]]])) (mf/defc text-menu {::mf/wrap [mf/memo]} [{:keys [ids type values] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - file-id (mf/use-ctx ctx/current-file-id) + (let [file-id (mf/use-ctx ctx/current-file-id) typographies (mf/deref refs/workspace-file-typography) shared-libs (mf/deref refs/workspace-libraries) label (case type @@ -411,87 +281,48 @@ (let [node (dom/get-element-by-class "public-DraftEditor-content")] (dom/focus! node))))))}] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? true - :collapsed? (not main-menu-open?) - :on-collapsed toggle-main-menu - :title label - :class (stl/css :title-spacing-text)} - (when (and (not typography) (not multiple?)) - [:button {:class (stl/css :add-typography) - :on-click on-convert-to-typography} - i/add-refactor])]] + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not main-menu-open?) + :on-collapsed toggle-main-menu + :title label + :class (stl/css :title-spacing-text)} + (when (and (not typography) (not multiple?)) + [:button {:class (stl/css :add-typography) + :on-click on-convert-to-typography} + i/add-refactor])]] - (when main-menu-open? - [:div {:class (stl/css :element-content)} - (cond - typography - [:& typography-entry {:typography typography - :local? (= typography-file file-id) - :file (get shared-libs typography-file) - :on-detach handle-detach-typography - :on-change handle-change-typography}] + (when main-menu-open? + [:div {:class (stl/css :element-content)} + (cond + typography + [:& typography-entry {:typography typography + :local? (= typography-file file-id) + :file (get shared-libs typography-file) + :on-detach handle-detach-typography + :on-change handle-change-typography}] - (= typography-id :multiple) - [:div {:class (stl/css :multiple-typography)} - [:span {:class (stl/css :multiple-text)} (tr "workspace.libraries.text.multiple-typography")] - [:div {:class (stl/css :multiple-typography-button) - :on-click handle-detach-typography - :title (tr "workspace.libraries.text.multiple-typography-tooltip")} - i/detach-refactor]] + (= typography-id :multiple) + [:div {:class (stl/css :multiple-typography)} + [:span {:class (stl/css :multiple-text)} (tr "workspace.libraries.text.multiple-typography")] + [:div {:class (stl/css :multiple-typography-button) + :on-click handle-detach-typography + :title (tr "workspace.libraries.text.multiple-typography-tooltip")} + i/detach-refactor]] - :else - [:> text-options opts]) + :else + [:> text-options opts]) - [:div {:class (stl/css :text-align-options)} - [:> text-align-options opts] - [:> grow-options opts] - [:button {:class (stl/css :more-options) - :on-click toggle-more-options} - i/menu-refactor]] - - (when more-options-open? - [:div {:class (stl/css :text-decoration-options)} - [:> vertical-align opts] - [:> text-decoration-options opts] - [:> text-direction-options opts]])])] - - - [:div.element-set - [:div.element-set-title - [:span label] - (when (and (not typography) (not multiple?)) - [:div.add-page {:on-click on-convert-to-typography} i/close])] - - (cond - typography - [:& typography-entry {:typography typography - :local? (= typography-file file-id) - :file (get shared-libs typography-file) - :on-detach handle-detach-typography - :on-change handle-change-typography}] - - (= typography-id :multiple) - [:div.multiple-typography - [:div.multiple-typography-text (tr "workspace.libraries.text.multiple-typography")] - [:div.multiple-typography-button {:on-click handle-detach-typography - :title (tr "workspace.libraries.text.multiple-typography-tooltip")} i/unchain]] - - :else - [:> text-options opts]) - - [:div.element-set-content - - [:div.row-flex + [:div {:class (stl/css :text-align-options)} [:> text-align-options opts] - [:> vertical-align opts]] - - [:div.row-flex - [:> text-decoration-options opts] - [:> text-direction-options opts]] - - [:div.row-flex [:> grow-options opts] - [:div.align-icons]]]]))) + [:button {:class (stl/css :more-options) + :on-click toggle-more-options} + i/menu-refactor]] + + (when more-options-open? + [:div {:class (stl/css :text-decoration-options)} + [:> vertical-align opts] + [:> text-decoration-options opts] + [:> text-direction-options opts]])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss index 2504fa5e78..2e0c982989 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss @@ -8,58 +8,68 @@ .element-set { margin: 0; - .element-title { - margin: 0; - .add-typography { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - .element-content { - @include flexColumn; - margin-top: $s-4; - .multiple-typography { - @extend .mixed-bar; - .multiple-text { - @include titleTipography; - flex-grow: 1; - color: var(--input-foreground-color-active); - } - .multiple-typography-button { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - .text-align-options { - display: flex; - gap: $s-4; - .align-options, - .text-direction-options, - .vertical-align-options, - .grow-options, - .text-decoration-options { - height: $s-32; - } - .more-options { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } - } - .text-decoration-options { - display: flex; - gap: $s-4; - } +} + +.element-title { + margin: 0; +} + +.add-typography { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; } } + +.element-content { + @include flexColumn; + margin-top: $s-4; +} + +.multiple-typography { + @extend .mixed-bar; +} + +.multiple-text { + @include titleTipography; + flex-grow: 1; + color: var(--input-foreground-color-active); +} + +.multiple-typography-button { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.text-align-options { + display: flex; + gap: $s-4; +} + +.align-options, +.text-direction-options, +.vertical-align-options, +.grow-options, +.text-decoration-options { + height: $s-32; +} + +.more-options { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.text-decoration-options { + display: flex; + gap: $s-4; +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs index 122c32ea8a..c54d3a13d5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs @@ -25,7 +25,6 @@ [app.main.ui.components.select :refer [select]] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] @@ -61,8 +60,7 @@ {::mf/wrap [mf/memo]} [{:keys [font current? on-click style]}] (let [item-ref (mf/use-ref) - on-click (mf/use-fn (mf/deps font) #(on-click font)) - new-css-system (mf/use-ctx ctx/new-css-system)] + on-click (mf/use-fn (mf/deps font) #(on-click font))] (mf/use-effect (mf/deps current?) @@ -72,22 +70,14 @@ (when-not (dom/is-in-viewport? element) (dom/scroll-into-view! element)))))) - (if new-css-system - [:div {:class (stl/css :font-wrapper) - :style style - :ref item-ref - :on-click on-click} - [:div {:class (stl/css-case :font-item true - :selected current?)} - [:span {:class (stl/css :label)} (:name font)] - [:span {:class (stl/css :icon)} (when current? i/tick-refactor)]]] - - [:div.font-item {:ref item-ref - :style style - :class (when current? "selected") - :on-click on-click} - [:span.icon (when current? i/tick)] - [:span.label (:name font)]]))) + [:div {:class (stl/css :font-wrapper) + :style style + :ref item-ref + :on-click on-click} + [:div {:class (stl/css-case :font-item true + :selected current?)} + [:span {:class (stl/css :label)} (:name font)] + [:span {:class (stl/css :icon)} (when current? i/tick-refactor)]]])) (declare row-renderer) @@ -104,8 +94,7 @@ (mf/defc font-selector [{:keys [on-select on-close current-font show-recent] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - selected (mf/use-state current-font) + (let [selected (mf/use-state current-font) state (mf/use-state {:term "" :backends #{}}) flist (mf/use-ref) @@ -143,12 +132,8 @@ on-filter-change (mf/use-fn - (mf/deps new-css-system) (fn [event] - (let [value (if new-css-system - event - (dom/get-target-val event))] - (swap! state assoc :term value)))) + (swap! state assoc :term event))) on-select-and-close (mf/use-fn @@ -184,72 +169,35 @@ #(let [offset (.getOffsetForRow ^js inst #js {:alignment "center" :index index})] (.scrollToPosition ^js inst offset))))) + [:div {:class (stl/css :font-selector)} + [:div {:class (stl/css :font-selector-dropdown)} + [:div {:class (stl/css :header)} + [:& search-bar {:on-change on-filter-change + :value (:term @state) + :placeholder (tr "workspace.options.search-font")}] + (when (and recent-fonts show-recent) + [* + [:p {:class (stl/css :title)} (tr "workspace.options.recent-fonts")] + (for [[idx font] (d/enumerate recent-fonts)] + [:& font-item {:key (dm/str "font-" idx) + :font font + :style {} + :on-click on-select-and-close + :current? (= (:id font) (:id @selected))}])])] - (if new-css-system - [:div {:class (stl/css :font-selector)} - [:div {:class (stl/css :font-selector-dropdown)} - [:div {:class (stl/css :header)} - [:& search-bar {:on-change on-filter-change - :value (:term @state) - :placeholder (tr "workspace.options.search-font")}] - (when (and recent-fonts show-recent) - [* - [:p {:class (stl/css :title)} (tr "workspace.options.recent-fonts")] - (for [[idx font] (d/enumerate recent-fonts)] - [:& font-item {:key (dm/str "font-" idx) - :font font - :style {} - :on-click on-select-and-close - :current? (= (:id font) (:id @selected))}])])] - - [:div {:class (stl/css :fonts-list)} - [:> rvt/AutoSizer {} - (fn [props] - (let [width (unchecked-get props "width") - height (unchecked-get props "height") - render #(row-renderer fonts @selected on-select-and-close %)] - (mf/html - [:> rvt/List #js {:height height - :ref flist - :width width - :rowCount (count fonts) - :rowHeight 36 - :rowRenderer render}])))]]]] - - [:div.font-selector - [:div.font-selector-dropdown - [:header - [:input {:placeholder (tr "workspace.options.search-font") - :value (:term @state) - :ref input - :spell-check false - :on-change on-filter-change}] - (when (and recent-fonts show-recent) - [:* - [:hr] - [:p.title (tr "workspace.options.recent-fonts")] - (for [[idx font] (d/enumerate recent-fonts)] - [:& font-item {:key (dm/str "font-" idx) - :font font - :style {} - :on-click on-select-and-close - :current? (= (:id font) (:id @selected))}])])] - - [:hr] - - [:div.fonts-list - [:> rvt/AutoSizer {} - (fn [props] - (let [width (unchecked-get props "width") - height (unchecked-get props "height") - render #(row-renderer fonts @selected on-select-and-close %)] - (mf/html - [:> rvt/List #js {:height height - :ref flist - :width width - :rowCount (count fonts) - :rowHeight 32 - :rowRenderer render}])))]]]]))) + [:div {:class (stl/css :fonts-list)} + [:> rvt/AutoSizer {} + (fn [props] + (let [width (unchecked-get props "width") + height (unchecked-get props "height") + render #(row-renderer fonts @selected on-select-and-close %)] + (mf/html + [:> rvt/List #js {:height height + :ref flist + :width width + :rowCount (count fonts) + :rowHeight 36 + :rowRenderer render}])))]]]])) (defn row-renderer [fonts selected on-select props] @@ -272,7 +220,6 @@ font-id (or font-id (:font-id txt/default-text-attrs)) font-size (or font-size (:font-size txt/default-text-attrs)) font-variant-id (or font-variant-id (:font-variant-id txt/default-text-attrs)) - new-css-system (mf/use-ctx ctx/new-css-system) fonts (mf/deref fonts/fontsdb) font (get fonts font-id) @@ -304,17 +251,14 @@ on-font-variant-change (mf/use-fn (mf/deps font on-change) - (fn [event] - (let [new-variant-id (if new-css-system - event - (dom/get-target-val event)) - variant (d/seek #(= new-variant-id (:id %)) (:variants font))] + (fn [new-variant-id] + (let [variant (d/seek #(= new-variant-id (:id %)) (:variants font))] (on-change {:font-id (:id font) :font-family (:family font) :font-variant-id new-variant-id :font-weight (:weight variant) :font-style (:style variant)}) - (dom/blur! (dom/get-target event))))) + (dom/blur! (dom/get-target new-variant-id))))) on-font-select (mf/use-fn @@ -335,114 +279,65 @@ (when (mf/ref-val last-font) (st/emit! (fts/add-recent-font (mf/ref-val last-font))))))] - (if new-css-system - [:* - (when @open-selector? - [:& font-selector - {:current-font font - :on-close on-font-selector-close - :on-select on-font-select - :show-recent show-recent}]) + [:* + (when @open-selector? + [:& font-selector + {:current-font font + :on-close on-font-selector-close + :on-select on-font-select + :show-recent show-recent}]) - [:div {:class (stl/css :font-option) - :on-click #(reset! open-selector? true)} - (cond - (= :multiple font-id) - "--" + [:div {:class (stl/css :font-option) + :on-click #(reset! open-selector? true)} + (cond + (= :multiple font-id) + "--" - (some? font) - [:* - [:span {:class (stl/css :name)} - (:name font)] - [:span {:class (stl/css :icon)} - i/arrow-refactor]] + (some? font) + [:* + [:span {:class (stl/css :name)} + (:name font)] + [:span {:class (stl/css :icon)} + i/arrow-refactor]] - :else - (tr "dashboard.fonts.deleted-placeholder"))] + :else + (tr "dashboard.fonts.deleted-placeholder"))] - [:div {:class (stl/css :font-modifiers)} - [:div {:class (stl/css :font-size-options)} - (let [size-options [8 9 10 11 12 14 16 18 24 36 48 72] - size-options (if (= font-size :multiple) (into [""] size-options) size-options)] - [:& editable-select - {:value (attr->string font-size) - :class (stl/css :font-size-select) - :input-class (stl/css :numeric-input) - :options size-options - :type "number" - :placeholder "--" - :min 3 - :max 1000 - :on-change on-font-size-change - :on-blur on-blur}])] + [:div {:class (stl/css :font-modifiers)} + [:div {:class (stl/css :font-size-options)} + (let [size-options [8 9 10 11 12 14 16 18 24 36 48 72] + size-options (if (= font-size :multiple) (into [""] size-options) size-options)] + [:& editable-select + {:value (attr->string font-size) + :class (stl/css :font-size-select) + :input-class (stl/css :numeric-input) + :options size-options + :type "number" + :placeholder "--" + :min 3 + :max 1000 + :on-change on-font-size-change + :on-blur on-blur}])] - [:div {:class (stl/css :font-variant-options)} - (let [basic-variant-options (->> (:variants font) - (map (fn [variant] - {:value (:id variant) - :key (pr-str variant) - :label (:name variant)}) )) - variant-options (if (= font-size :multiple) - (conj basic-variant-options - {:value :multiple - :key :multiple-variants - :label "--"} ) - basic-variant-options)] - ;; TODO Add disabled mode - [:& select - {:class (stl/css :font-variant-select) - :default-value (attr->string font-variant-id) - :options variant-options - :on-change on-font-variant-change - :on-blur on-blur}])]]] - - [:* - (when @open-selector? - [:& font-selector - {:current-font font - :on-close on-font-selector-close - :on-select on-font-select - :show-recent show-recent}]) - - [:div.row-flex - [:div.input-select.font-option - {:on-click #(reset! open-selector? true)} - (cond - (= :multiple font-id) - "--" - - (some? font) - (:name font) - - :else - (tr "dashboard.fonts.deleted-placeholder"))]] - - [:div.row-flex - (let [size-options [8 9 10 11 12 14 16 18 24 36 48 72] - size-options (if (= font-size :multiple) (into [""] size-options) size-options)] - [:& editable-select - {:value (attr->string font-size) - :class "input-option size-option" - :options size-options - :type "number" - :placeholder "--" - :min 3 - :max 1000 - :on-change on-font-size-change - :on-blur on-blur}]) - - [:select.input-select.variant-option - {:disabled (= font-id :multiple) - :data-mousetrap-dont-stop true - :value (attr->string font-variant-id) - :on-change on-font-variant-change - :on-blur on-blur} - (when (or (= font-id :multiple) (= font-variant-id :multiple)) - [:option {:value ""} "--"]) - (for [variant (:variants font)] - [:option {:value (:id variant) - :key (pr-str variant)} - (:name variant)])]]]))) + [:div {:class (stl/css :font-variant-options)} + (let [basic-variant-options (->> (:variants font) + (map (fn [variant] + {:value (:id variant) + :key (pr-str variant) + :label (:name variant)}))) + variant-options (if (= font-size :multiple) + (conj basic-variant-options + {:value :multiple + :key :multiple-variants + :label "--"}) + basic-variant-options)] + ;; TODO Add disabled mode + [:& select + {:class (stl/css :font-variant-select) + :default-value (attr->string font-variant-id) + :options variant-options + :on-change on-font-variant-change + :on-blur on-blur}])]]])) (mf/defc spacing-options {::mf/wrap-props false} @@ -452,152 +347,87 @@ line-height (or line-height "1.2") letter-spacing (or letter-spacing "0") - new-css-system (mf/use-ctx ctx/new-css-system) line-height-nillable (if (= (str line-height) "1.2") false true) handle-change (fn [value attr] (on-change {attr (str value)}))] - (if new-css-system - [:div {:class (stl/css :spacing-options)} - [:div {:class (stl/css :line-height)} - [:span {:class (stl/css :icon) - :alt (tr "workspace.options.text-options.line-height")} - i/text-lineheight-refactor] - [:> numeric-input* - {:min -200 - :max 200 - :step 0.1 - :default "1.2" - :class (stl/css :line-height-input) - :value (attr->string line-height) - :placeholder (tr "settings.multiple") - :nillable line-height-nillable - :on-change #(handle-change % :line-height) - :on-blur on-blur}]] - [:div {:class (stl/css :letter-spacing)} - [:span - {:class (stl/css :icon) - :alt (tr "workspace.options.text-options.letter-spacing")} - i/text-letterspacing-refactor] - [:> numeric-input* - {:min -200 - :max 200 - :step 0.1 - :class (stl/css :letter-spacing-input) - :value (attr->string letter-spacing) - :placeholder (tr "settings.multiple") - :on-change #(handle-change % :letter-spacing) - :on-blur on-blur}]]] + [:div {:class (stl/css :spacing-options)} + [:div {:class (stl/css :line-height)} + [:span {:class (stl/css :icon) + :alt (tr "workspace.options.text-options.line-height")} + i/text-lineheight-refactor] + [:> numeric-input* + {:min -200 + :max 200 + :step 0.1 + :default "1.2" + :class (stl/css :line-height-input) + :value (attr->string line-height) + :placeholder (tr "settings.multiple") + :nillable line-height-nillable + :on-change #(handle-change % :line-height) + :on-blur on-blur}]] - - [:div.spacing-options - [:div.input-icon - [:span.icon-before.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.line-height")} - i/line-height] - [:> numeric-input* - {:min -200 - :max 200 - :step 0.1 - :default "1.2" - :value (attr->string line-height) - :placeholder (tr "settings.multiple") - :nillable line-height-nillable - :on-change #(handle-change % :line-height) - :on-blur on-blur}]] - - [:div.input-icon - [:span.icon-before.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.letter-spacing")} - i/letter-spacing] - [:> numeric-input* - {:min -200 - :max 200 - :step 0.1 - :value (attr->string letter-spacing) - :placeholder (tr "settings.multiple") - :on-change #(handle-change % :letter-spacing) - :on-blur on-blur}]]]))) + [:div {:class (stl/css :letter-spacing)} + [:span + {:class (stl/css :icon) + :alt (tr "workspace.options.text-options.letter-spacing")} + i/text-letterspacing-refactor] + [:> numeric-input* + {:min -200 + :max 200 + :step 0.1 + :class (stl/css :letter-spacing-input) + :value (attr->string letter-spacing) + :placeholder (tr "settings.multiple") + :on-change #(handle-change % :letter-spacing) + :on-blur on-blur}]]])) (mf/defc text-transform-options {::mf/wrap-props false} [{:keys [values on-change on-blur]}] (let [text-transform (or (:text-transform values) "none") - new-css-system (mf/use-ctx ctx/new-css-system) handle-change (fn [type] (if (= text-transform type) (on-change {:text-transform "unset"}) (on-change {:text-transform type})) (when (some? on-blur) (on-blur)))] - (if new-css-system - [:div {:class (stl/css :text-transform)} - [:& radio-buttons {:selected text-transform - :on-change handle-change - :name "text-transform"} - [:& radio-button {:icon i/text-uppercase-refactor - :type "checkbox" - :value "uppercase" - :id "text-transform-uppercase"}] - [:& radio-button {:icon i/text-lowercase-refactor - :type "checkbox" - :value "lowercase" - :id "text-transform-lowercase"}] - [:& radio-button {:icon i/text-mixed-refactor - :type "checkbox" - :value "capitalize" - :id "text-transform-capitalize"}]]] - [:div.align-icons - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.none") - :class (dom/classnames :current (= "none" text-transform)) - :on-focus #(dom/prevent-default %) - :on-click #(handle-change "none")} - i/minus] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.uppercase") - :class (dom/classnames :current (= "uppercase" text-transform)) - :on-click #(handle-change "uppercase")} - i/uppercase] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.lowercase") - :class (dom/classnames :current (= "lowercase" text-transform)) - :on-click #(handle-change "lowercase")} - i/lowercase] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.titlecase") - :class (dom/classnames :current (= "capitalize" text-transform)) - :on-click #(handle-change "capitalize")} - i/titlecase]]))) + [:div {:class (stl/css :text-transform)} + [:& radio-buttons {:selected text-transform + :on-change handle-change + :name "text-transform"} + [:& radio-button {:icon i/text-uppercase-refactor + :type "checkbox" + :value "uppercase" + :id "text-transform-uppercase"}] + [:& radio-button {:icon i/text-lowercase-refactor + :type "checkbox" + :value "lowercase" + :id "text-transform-lowercase"}] + [:& radio-button {:icon i/text-mixed-refactor + :type "checkbox" + :value "capitalize" + :id "text-transform-capitalize"}]]])) (mf/defc text-options {::mf/wrap-props false} [{:keys [ids editor values on-change on-blur show-recent]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - opts #js {:editor editor + (let [opts #js {:editor editor :ids ids :values values :on-change on-change :on-blur on-blur :show-recent show-recent}] - (if new-css-system - [:div {:class (stl/css :text-options)} - [:> font-options opts] - [:div {:class (stl/css :typography-variations)} - [:> spacing-options opts] - [:> text-transform-options opts]]] - - [:div.element-set-content - [:> font-options opts] - [:div.row-flex - [:> spacing-options opts]] - [:div.row-flex - [:> text-transform-options opts]]]))) - + [:div {:class (stl/css :text-options)} + [:> font-options opts] + [:div {:class (stl/css :typography-variations)} + [:> spacing-options opts] + [:> text-transform-options opts]]])) (mf/defc typography-advanced-options {::mf/wrap [mf/memo]} @@ -684,16 +514,11 @@ :on-click navigate-to-library} (tr "workspace.assets.typography.go-to-edit")])])]))) - (mf/defc typography-entry {::mf/wrap-props false} [{:keys [file-id typography local? selected? on-click on-change on-detach on-context-menu editing? renaming? focus-name? external-open*]}] - (let [hover-detach* (mf/use-state false) - hover-detach? (deref hover-detach*) - - name-input-ref (mf/use-ref) + (let [name-input-ref (mf/use-ref) read-only? (mf/use-ctx ctx/workspace-read-only?) - new-css-system (mf/use-ctx ctx/new-css-system) editable? (and local? (not read-only?)) open* (mf/use-state editing?) @@ -710,12 +535,6 @@ (on-change {:name name}) (st/emit! #(update % :workspace-global dissoc :rename-typography)))))) - on-pointer-enter - (mf/use-fn #(reset! hover-detach* true)) - - on-pointer-leave - (mf/use-fn #(reset! hover-detach* false)) - on-open (mf/use-fn #(reset! open* true)) @@ -755,147 +574,62 @@ (dom/focus! node) (dom/select-text! node))))) - (if new-css-system - [:* - [:div {:class (stl/css-case :typography-entry true - :selected ^boolean selected?) - :style {:display (when ^boolean open? "none")}} - (if renaming? - [:div {:class (stl/css :font-name-wrapper)} - [:div - {:class (stl/css :typography-sample-input) - :style {:font-family (:font-family typography) - :font-weight (:font-weight typography) - :font-style (:font-style typography)}} - (tr "workspace.assets.typography.sample")] - - [:input - {:class (stl/css :adv-typography-name) - :type "text" - :ref name-input-ref - :default-value (:name typography) - :on-key-down on-key-down - :on-blur on-name-blur}]] - [:div - {:class (stl/css-case :typography-selection-wrapper true - :is-selectable ^boolean on-click) - :on-click on-click - :on-context-menu on-context-menu} - [:div - {:class (stl/css :typography-sample) - :style {:font-family (:font-family typography) - :font-weight (:font-weight typography) - :font-style (:font-style typography)}} - (tr "workspace.assets.typography.sample")] - - [:div {:class (stl/css :typography-name) - :title (:name typography)} (:name typography)] - - (when-not name-only? - [:div {:class (stl/css :typography-font) - :title (:name font-data)} - (:name font-data)])]) - [:div {:class (stl/css :element-set-actions)} - (when ^boolean on-detach - [:button {:class (stl/css :element-set-actions-button) - :on-click on-detach} - i/detach-refactor]) - [:button {:class (stl/css :menu-btn) - :on-click on-open} - i/menu-refactor]]] - - [:& typography-advanced-options - {:visible? open? - :on-close on-close - :typography typography - :editable? editable? - :name-input-ref name-input-ref - :on-change on-change - :on-name-blur on-name-blur - :on-key-down on-key-down - :local? local? - :navigate-to-library navigate-to-library}]] - - - [:* - [:div.element-set-options-group.typography-entry - {:class (when ^boolean selected? "selected") - :style {:display (when ^boolean open? "none")}} - [:div.typography-selection-wrapper - {:class (when ^boolean on-click "is-selectable") - :on-click on-click - :on-context-menu on-context-menu} - [:div.typography-sample - {:style {:font-family (:font-family typography) + [:* + [:div {:class (stl/css-case :typography-entry true + :selected ^boolean selected?) + :style {:display (when ^boolean open? "none")}} + (if renaming? + [:div {:class (stl/css :font-name-wrapper)} + [:div + {:class (stl/css :typography-sample-input) + :style {:font-family (:font-family typography) :font-weight (:font-weight typography) :font-style (:font-style typography)}} (tr "workspace.assets.typography.sample")] - [:div.typography-name {:title (:name typography)} (:name typography)]] - [:div.element-set-actions - (when ^boolean on-detach - [:div.element-set-actions-button - {:on-pointer-enter on-pointer-enter - :on-pointer-leave on-pointer-leave - :on-click on-detach} - (if ^boolean hover-detach? i/unchain i/chain)]) - [:div.element-set-actions-button - {:on-click on-open} - i/actions]]] + [:input + {:class (stl/css :adv-typography-name) + :type "text" + :ref name-input-ref + :default-value (:name typography) + :on-key-down on-key-down + :on-blur on-name-blur}]] + [:div + {:class (stl/css-case :typography-selection-wrapper true + :is-selectable ^boolean on-click) + :on-click on-click + :on-context-menu on-context-menu} + [:div + {:class (stl/css :typography-sample) + :style {:font-family (:font-family typography) + :font-weight (:font-weight typography) + :font-style (:font-style typography)}} + (tr "workspace.assets.typography.sample")] - [:& advanced-options {:visible? open? :on-close on-close} - (if ^boolean editable? - [:* - [:div.element-set-content - [:div.row-flex - [:input.element-name.adv-typography-name - {:type "text" - :ref name-input-ref - :default-value (:name typography) - :on-blur on-name-blur}] + [:div {:class (stl/css :typography-name) + :title (:name typography)} (:name typography)] - [:div.element-set-actions-button - {:on-click on-close} - i/actions]]] + (when-not name-only? + [:div {:class (stl/css :typography-font) + :title (:name font-data)} + (:name font-data)])]) + [:div {:class (stl/css :element-set-actions)} + (when ^boolean on-detach + [:button {:class (stl/css :element-set-actions-button) + :on-click on-detach} + i/detach-refactor]) + [:button {:class (stl/css :menu-btn) + :on-click on-open} + i/menu-refactor]]] - [:& text-options {:values typography - :on-change on-change - :show-recent false}]] - - [:div.element-set-content.typography-read-only-data - [:div.row-flex.typography-name - [:span {:title (:name typography)} (:name typography)]] - - [:div.row-flex - [:span.label (tr "workspace.assets.typography.font-id")] - [:span (:font-id typography)]] - - [:div.element-set-actions-button.actions-inside - {:on-click on-close} - i/actions] - - [:div.row-flex - [:span.label (tr "workspace.assets.typography.font-variant-id")] - [:span (:font-variant-id typography)]] - - [:div.row-flex - [:span.label (tr "workspace.assets.typography.font-size")] - [:span (:font-size typography)]] - - [:div.row-flex - [:span.label (tr "workspace.assets.typography.line-height")] - [:span (:line-height typography)]] - - [:div.row-flex - [:span.label (tr "workspace.assets.typography.letter-spacing")] - [:span (:letter-spacing typography)]] - - [:div.row-flex - [:span.label (tr "workspace.assets.typography.text-transform")] - [:span (:text-transform typography)]] - - (when-not local? - [:div.row-flex - [:a.go-to-lib-button - {:on-click navigate-to-library} - (tr "workspace.assets.typography.go-to-edit")]])])]]))) + [:& typography-advanced-options + {:visible? open? + :on-close on-close + :typography typography + :editable? editable? + :name-input-ref name-input-ref + :on-change on-change + :on-name-blur on-name-blur + :on-key-down on-key-down + :local? local? + :navigate-to-library navigate-to-library}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss index 305fc6e83e..6f7aab290d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss @@ -142,103 +142,104 @@ height: 100%; width: 100%; background-color: var(--assets-title-background-color); - .typography-info-wrapper { - @include flexColumn; - margin-bottom: $s-12; - .typography-name-wrapper { - @extend .asset-element; - display: grid; - grid-template-columns: $s-24 auto 1fr $s-28; - flex: 1; +} + +.typography-info-wrapper { + @include flexColumn; + margin-bottom: $s-12; + .typography-name-wrapper { + @extend .asset-element; + display: grid; + grid-template-columns: $s-24 auto 1fr $s-28; + flex: 1; + height: $s-32; + width: 100%; + padding: 0 0 0 $s-12; + background-color: var(--assets-item-background-color-hover); + margin-bottom: $s-4; + .typography-sample { + @include flexCenter; + min-width: $s-24; + font-size: $fs-16; height: $s-32; - width: 100%; - padding: 0 0 0 $s-12; - background-color: var(--assets-item-background-color-hover); - margin-bottom: $s-4; - .typography-sample { - @include flexCenter; - min-width: $s-24; - font-size: $fs-16; - height: $s-32; - padding: 0; - color: var(--assets-item-name-foreground-color-hover); + padding: 0; + color: var(--assets-item-name-foreground-color-hover); + } + .typography-name { + @include titleTipography; + @include textEllipsis; + display: flex; + align-items: center; + justify-content: flex-start; + margin-left: $s-6; + color: var(--assets-item-name-foreground-color-hover); + } + .typography-font { + @include titleTipography; + @include textEllipsis; + margin-left: $s-6; + display: flex; + align-items: center; + justify-content: flex-start; + min-width: 0; + color: var(--assets-item-name-foreground-color); + } + .action-btn { + @extend .button-tertiary; + width: $s-28; + height: $s-32; + svg { + @extend .button-icon; } - .typography-name { - @include titleTipography; - @include textEllipsis; - display: flex; - align-items: center; - justify-content: flex-start; - margin-left: $s-6; - color: var(--assets-item-name-foreground-color-hover); - } - .typography-font { - @include titleTipography; - @include textEllipsis; - margin-left: $s-6; - display: flex; - align-items: center; - justify-content: flex-start; - min-width: 0; - color: var(--assets-item-name-foreground-color); - } - .action-btn { - @extend .button-tertiary; - width: $s-28; - height: $s-32; - svg { - @extend .button-icon; - } - &:active { - background-color: transparent; - } + &:active { + background-color: transparent; } } + } - .info-row { - display: grid; - grid-template-columns: 50% 50%; - height: $s-32; - --calcualted-width: calc(var(--width) - $s-48); - padding-left: $s-2; - .info-label { - @include titleTipography; - @include textEllipsis; - width: calc(var(--calcualted-width) / 2); - padding-top: $s-8; - color: var(--assets-item-name-foreground-color); - } - .info-content { - @include titleTipography; - @include textEllipsis; - padding-top: $s-8; - width: calc(var(--calcualted-width) / 2); - color: var(--assets-item-name-foreground-color-hover); + .info-row { + display: grid; + grid-template-columns: 50% 50%; + height: $s-32; + --calcualted-width: calc(var(--width) - $s-48); + padding-left: $s-2; + .info-label { + @include titleTipography; + @include textEllipsis; + width: calc(var(--calcualted-width) / 2); + padding-top: $s-8; + color: var(--assets-item-name-foreground-color); + } + .info-content { + @include titleTipography; + @include textEllipsis; + padding-top: $s-8; + width: calc(var(--calcualted-width) / 2); + color: var(--assets-item-name-foreground-color-hover); + } + } + + .link-btn { + @include tabTitleTipography; + @extend .button-secondary; + width: 100%; + height: $s-32; + border-radius: $br-8; + &:hover { + background-color: var(--button-secondary-background-color-hover); + color: var(--button-secondary-foreground-color-hover); + border: $s-1 solid var(--button-secondary-border-color-hover); + text-decoration: none; + svg { + stroke: var(--button-secondary-foreground-color-hover); } } - - .link-btn { - @include tabTitleTipography; - @extend .button-secondary; - width: 100%; - height: $s-32; - border-radius: $br-8; - &:hover { - background-color: var(--button-secondary-background-color-hover); - color: var(--button-secondary-foreground-color-hover); - border: $s-1 solid var(--button-secondary-border-color-hover); - text-decoration: none; - svg { - stroke: var(--button-secondary-foreground-color-hover); - } - } - &:focus { - background-color: var(--button-secondary-background-color-focus); - color: var(--button-secondary-foreground-color-focus); - border: $s-1 solid var(--button-secondary-border-color-focus); - svg { - stroke: var(--button-secondary-foreground-color-focus); - } + &:focus { + background-color: var(--button-secondary-background-color-focus); + color: var(--button-secondary-foreground-color-focus); + border: $s-1 solid var(--button-secondary-border-color-focus); + svg { + stroke: var(--button-secondary-foreground-color-focus); } } } From 452289b7264594261efc570e6ef862607018519c Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 2 Jan 2024 17:01:52 +0100 Subject: [PATCH 10/35] :recycle: Remove new-css-system from colorpicker --- frontend/resources/styles/main-default.scss | 3 - .../styles/main/partials/colorpicker.scss | 598 ---- .../main/partials/sidebar-align-options.scss | 62 - .../partials/sidebar-element-options.scss | 2593 ----------------- .../app/main/ui/workspace/colorpicker.cljs | 327 +-- .../app/main/ui/workspace/colorpicker.scss | 272 +- .../ui/workspace/colorpicker/gradients.cljs | 53 +- .../ui/workspace/colorpicker/gradients.scss | 66 +- .../ui/workspace/colorpicker/harmony.cljs | 127 +- .../ui/workspace/colorpicker/harmony.scss | 57 +- .../main/ui/workspace/colorpicker/hsva.cljs | 121 +- .../main/ui/workspace/colorpicker/hsva.scss | 31 +- .../ui/workspace/colorpicker/libraries.cljs | 91 +- .../ui/workspace/colorpicker/libraries.scss | 52 +- .../main/ui/workspace/colorpicker/ramp.cljs | 121 +- .../main/ui/workspace/colorpicker/ramp.scss | 16 +- .../colorpicker/slider_selector.cljs | 70 +- 17 files changed, 549 insertions(+), 4111 deletions(-) delete mode 100644 frontend/resources/styles/main/partials/colorpicker.scss delete mode 100644 frontend/resources/styles/main/partials/sidebar-align-options.scss delete mode 100644 frontend/resources/styles/main/partials/sidebar-element-options.scss diff --git a/frontend/resources/styles/main-default.scss b/frontend/resources/styles/main-default.scss index 9271b633a6..8243d1bb70 100644 --- a/frontend/resources/styles/main-default.scss +++ b/frontend/resources/styles/main-default.scss @@ -58,7 +58,6 @@ @import "main/partials/viewer-header"; @import "main/partials/viewer-thumbnails"; @import "main/partials/activity-bar"; -@import "main/partials/colorpicker"; @import "main/partials/dashboard"; @import "main/partials/dashboard-header"; @import "main/partials/dashboard-grid"; @@ -71,9 +70,7 @@ @import "main/partials/loader"; @import "main/partials/project-bar"; @import "main/partials/sidebar"; -@import "main/partials/sidebar-align-options"; @import "main/partials/sidebar-document-history"; -@import "main/partials/sidebar-element-options"; @import "main/partials/sidebar-interactions"; @import "main/partials/tab-container"; @import "main/partials/tool-bar"; diff --git a/frontend/resources/styles/main/partials/colorpicker.scss b/frontend/resources/styles/main/partials/colorpicker.scss deleted file mode 100644 index e70546d659..0000000000 --- a/frontend/resources/styles/main/partials/colorpicker.scss +++ /dev/null @@ -1,598 +0,0 @@ -// 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 - -.colorpicker { - box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); - background-color: $color-white; -} - -.colorpicker-content { - display: flex; - flex-direction: column; - padding: $size-2; - - & > * { - width: 200px; - } - - .top-actions { - display: flex; - margin-bottom: $size-1; - flex-direction: row-reverse; - justify-content: space-between; - - .picker-btn { - background: none; - border: none; - cursor: pointer; - - &.active svg, - &:hover svg { - fill: $color-primary; - } - - svg { - width: 14px; - height: 14px; - } - } - - .element-set-content { - width: auto; - padding: 0.25rem 0; - .custom-select { - border: none; - &:hover { - border: none; - } - .custom-select-dropdown { - left: auto; - right: 0; - } - } - } - } - - .select-image { - .content { - display: flex; - justify-content: center; - background-image: url("/images/colorpicker-no-image.png"); - background-position: center; - background-size: auto 6.75rem; - height: 6.75rem; - img { - height: fit-content; - width: fit-content; - max-height: 100%; - max-width: 100%; - margin: auto; - } - } - button { - width: 100%; - margin-top: 10px; - } - } - .gradients-buttons { - .gradient { - cursor: pointer; - width: 15px; - height: 15px; - padding: 0; - margin: 0; - border: 1px solid $color-gray-20; - border-radius: $br2; - margin-left: $size-1; - } - - .active { - border-color: $color-primary; - } - - .linear-gradient { - background: linear-gradient(180deg, $color-gray-20, transparent); - } - - .radial-gradient { - background: radial-gradient(transparent, $color-gray-20); - } - } - - .gradient-stops { - height: 10px; - display: flex; - margin-top: $size-2; - margin-bottom: $size-4; - - .gradient-background-wrapper { - height: 100%; - width: 100%; - border: 1px solid $color-gray-10; - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") - left center; - } - - .gradient-background { - height: 100%; - width: 100%; - } - - .gradient-stop-wrapper { - position: absolute; - width: calc(100% - 2rem); - margin-left: 0.5rem; - } - - .gradient-stop { - display: grid; - grid-template-columns: 50% 50%; - position: absolute; - width: 15px; - height: 15px; - border-radius: $br2; - border: 1px solid $color-gray-20; - margin-top: -2px; - margin-left: -7px; - box-shadow: 0 2px 2px rgb(0 0 0 / 15%); - - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") - left center; - background-color: $color-white; - - &.active { - border-color: $color-primary; - } - } - } - - .picker-detail-wrapper { - position: relative; - - .center-circle { - width: 14px; - height: 14px; - border: 2px solid $color-white; - border-radius: $br8; - position: absolute; - left: 50%; - top: 50%; - transform: translate(-7px, -7px); - filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25)); - } - } - - #picker-detail { - border: 1px solid $color-gray-10; - } - - .slider-selector { - --gradient-direction: 90deg; - --background-repeat: left; - - &.vertical { - --gradient-direction: 0deg; - --background-repeat: top; - } - - border: 1px solid $color-gray-10; - - background: linear-gradient( - var(--gradient-direction), - rgba(var(--color), 0) 0%, - rgba(var(--color), 1) 100% - ); - align-self: center; - position: relative; - cursor: pointer; - - width: 100%; - height: calc(0.5rem + 1px); - - &.vertical { - width: calc(0.5rem + 1px); - height: 100%; - } - - &.hue { - background: linear-gradient( - var(--gradient-direction), - #f00 0%, - #ff0 17%, - #0f0 33%, - #0ff 50%, - #00f 67%, - #f0f 83%, - #f00 100% - ); - } - - &.saturation { - background: linear-gradient( - var(--gradient-direction), - var(--saturation-grad-from) 0%, - var(--saturation-grad-to) 100% - ); - } - - &.opacity { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") - var(--background-repeat) center; - - &::after { - content: ""; - position: absolute; - width: 100%; - height: 100%; - background: linear-gradient( - var(--gradient-direction), - rgba(var(--color), 0) 0%, - rgba(var(--color), 1) 100% - ); - } - } - - &.value { - background: linear-gradient(var(--gradient-direction), #000 0%, #fff 100%); - } - - .handler { - background-color: $color-white; - box-shadow: rgba(0, 0, 0, 0.37) 0px 1px 4px 0px; - transform: translate(-6px, -2px); - left: 50%; - position: absolute; - width: 12px; - height: 12px; - border-radius: $br6; - z-index: 1; - } - - &.vertical .handler { - transform: translate(-6px, 6px); - } - } - - .value-saturation-selector { - background-color: rgba(var(--hue-rgb)); - position: relative; - height: 6.75rem; - cursor: pointer; - - .handler { - position: absolute; - width: 12px; - height: 12px; - border-radius: $br6; - z-index: 1; - border: 1px solid $color-white; - box-shadow: - rgb(255, 255, 255) 0px 0px 0px 1px inset, - rgb(0 0 0 / 0.25) 0px 4px 4px inset, - rgb(0 0 0 / 0.25) 0px 4px 4px; - transform: translate(-6px, -6px); - left: 50%; - top: 50%; - } - - &::before { - content: ""; - position: absolute; - width: 100%; - height: 100%; - background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0)); - } - - &::after { - content: ""; - position: absolute; - width: 100%; - height: 100%; - background: linear-gradient(to top, #000, rgba(0, 0, 0, 0)); - } - } - - .shade-selector { - display: grid; - justify-items: center; - align-items: center; - grid-template-areas: - "color hue" - "color opacity"; - grid-template-columns: 2.5rem 1fr; - height: 3.5rem; - grid-row-gap: 0.5rem; - cursor: pointer; - margin-bottom: 0.25rem; - - .slider-selector.hue { - grid-area: "hue"; - align-self: flex-end; - } - - .slider-selector.opacity { - grid-area: "opacity"; - align-self: flex-start; - } - } - - .color-values { - display: grid; - grid-template-columns: 3.5rem repeat(4, 1fr); - grid-row-gap: 0.25rem; - justify-items: center; - grid-column-gap: 0.25rem; - - &.disable-opacity { - grid-template-columns: 3.5rem repeat(3, 1fr); - } - - input { - width: 100%; - margin: 0; - border: 1px solid $color-gray-10; - border-radius: $br2; - font-size: $fs12; - height: 1.5rem; - padding: 0 $size-1; - color: $color-gray-40; - } - - label { - font-size: $fs12; - } - } - - .libraries { - border-top: 1px solid $color-gray-10; - padding-top: 0.5rem; - margin-top: 0.25rem; - width: 200px; - - select { - background-image: url(/images/icons/arrow-down.svg); - background-repeat: no-repeat; - background-position: 95% 48%; - background-size: 10px; - margin: 0; - margin-bottom: $size-2; - width: 100%; - padding: $size-1 0.25rem; - font-size: $fs12; - color: $color-gray-40; - cursor: pointer; - border: 1px solid $color-gray-10; - border-radius: $br2; - - option { - padding: 0; - } - } - - .selected-colors { - display: grid; - grid-template-columns: repeat(8, 1fr); - justify-content: space-between; - margin-right: -8px; - max-height: 5.5rem; - overflow: auto; - div { - grid-area: unset; - } - } - - .selected-colors::after { - content: ""; - flex: auto; - } - } - - .actions { - margin-top: 0.5rem; - display: flex; - flex-direction: row; - justify-content: center; - - .btn-primary { - height: 1.5rem; - font-size: $fs12; - width: 100%; - } - } - - .harmony-selector { - display: flex; - flex-direction: row; - margin-bottom: 0.5rem; - - .hue-wheel-wrapper { - position: relative; - - .hue-wheel { - width: 152px; - height: 152px; - } - - .handler { - position: absolute; - width: 12px; - height: 12px; - border-radius: $br6; - z-index: 1; - border: 1px solid $color-white; - box-shadow: - rgb(255, 255, 255) 0px 0px 0px 1px inset, - rgb(0 0 0 / 0.25) 0px 4px 4px inset, - rgb(0 0 0 / 0.25) 0px 4px 4px; - transform: translate(-6px, -6px); - left: 50%; - top: 50%; - } - - .handler.complement { - background-color: $color-white; - box-shadow: rgb(0 0 0 / 0.25) 0px 4px 4px; - } - } - - .handlers-wrapper { - height: 152px; - display: flex; - flex-direction: row; - flex-grow: 1; - justify-content: space-around; - padding-top: 0.5rem; - - & > * { - height: 100%; - } - } - } - - .hsva-selector { - display: grid; - padding: 0.25rem; - grid-template-columns: 20px 1fr; - grid-template-rows: repeat(4, 2rem); - grid-row-gap: 0.5rem; - margin-bottom: 0.5rem; - - .hue, - .saturation, - .value, - .opacity { - border-radius: $br10; - } - - .hsva-selector-label { - grid-column: 1; - align-self: center; - } - } -} - -.colorpicker-tooltip { - border-radius: $br3; - display: flex; - flex-direction: column; - left: 1400px; - top: 100px; - position: absolute; - z-index: 11; - width: auto; - - span { - color: $color-gray-20; - font-size: $fs12; - } - - .inputs-area { - .input-text { - color: $color-gray-60; - font-size: $fs12; - margin: 5px; - padding: 5px; - width: 100%; - } - } - - .colorpicker-tabs { - display: flex; - margin-bottom: $size-2; - border-radius: $br5; - border: 1px solid $color-gray-10; - height: 2rem; - - .colorpicker-tab { - cursor: pointer; - display: flex; - flex-grow: 1; - justify-content: center; - align-items: center; - - svg { - width: 16px; - height: 16px; - fill: $color-gray-20; - } - } - - .active { - background-color: $color-gray-10; - svg { - fill: $color-gray-60; - } - } - - :hover svg { - fill: $color-primary; - } - } -} - -.color-data { - align-items: center; - display: flex; - margin-bottom: $size-2; - position: relative; - - &[draggable="true"] { - cursor: pointer; - } - - .color-name { - font-size: $fs12; - margin: 5px 6px 0px 6px; - } - - .color-info { - flex: 1 1 0; - - input { - background-color: $color-gray-50; - border: 1px solid $color-gray-30; - border-radius: $br3; - color: $color-white; - height: 20px; - margin: 5px 0 0 0; - padding: 0 $size-1; - width: 84px; - font-size: $fs12; - - &:focus { - border-color: $color-primary !important; - color: $color-white; - outline: none; - } - - &:hover { - border-color: $color-gray-20; - } - - &:invalid { - border-color: $color-danger; - } - } - } - - ::placeholder { - color: $color-gray-10; - } - - .type { - color: $color-gray-10; - margin-right: $size-1; - } - - .number { - color: $color-gray-60; - } - - .element-set-actions-button svg { - width: 10px; - height: 10px; - } -} diff --git a/frontend/resources/styles/main/partials/sidebar-align-options.scss b/frontend/resources/styles/main/partials/sidebar-align-options.scss deleted file mode 100644 index b792e060c2..0000000000 --- a/frontend/resources/styles/main/partials/sidebar-align-options.scss +++ /dev/null @@ -1,62 +0,0 @@ -// 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 - -.align-options { - display: flex; - border-bottom: solid 1px $color-gray-60; - height: 40px; - - .align-group { - padding: 0 $size-1; - display: flex; - justify-content: flex-start; - width: 50%; - - &:not(:last-child) { - border-right: solid 1px $color-gray-60; - } - } - - .align-button { - align-items: center; - cursor: pointer; - display: flex; - height: 30px; - justify-content: center; - margin: 5px 0; - padding: $size-2 $size-1; - width: 25%; - - svg { - height: 16px; - width: 16px; - fill: $color-gray-20; - } - - &:hover { - background-color: $color-primary; - svg { - fill: $color-gray-50; - } - } - - &.disabled { - background-color: transparent; - cursor: default; - svg { - fill: $color-gray-40; - } - } - - &.selected svg { - fill: $color-primary; - } - - &.selected:hover svg { - fill: $color-white; - } - } -} diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss deleted file mode 100644 index 5dab0ad90b..0000000000 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ /dev/null @@ -1,2593 +0,0 @@ -// 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 - -.element-options { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - - .element-icons { - background-color: $color-gray-60; - border: 1px solid $color-gray-60; - border-radius: $br3; - display: flex; - margin: $size-1; - - li { - align-items: center; - border-right: 1px solid $color-gray-60; - border-radius: $br3; - cursor: pointer; - display: flex; - flex: 1; - justify-content: center; - padding: $size-2; - - svg { - fill: $color-gray-20; - height: 15px; - width: 15px; - } - - &:hover { - svg { - fill: $color-primary; - } - } - - &.selected { - background-color: $color-primary; - - svg { - fill: $color-white; - } - } - - &:last-child { - border: none; - } - } - } - - &.inspect { - & > :first-child { - margin-top: 7px; - } - } - - .element-set { - border-bottom: 1px solid $color-gray-60; - color: $color-gray-20; - padding: $size-2 $size-1; - - .element-set-title { - height: 35px; - color: $color-gray-20; - display: flex; - font-size: $fs14; - padding: $size-1; - width: 100%; - align-items: center; - justify-content: space-between; - } - } - - .element-list { - margin-bottom: $size-2; - - li { - align-items: center; - border-bottom: 1px solid $color-gray-60; - display: flex; - flex-direction: row; - padding: $size-2; - width: 100%; - - .list-icon { - svg { - fill: $color-gray-30; - height: 15px; - margin-right: $size-1; - width: 15px; - } - } - - span { - color: $color-gray-20; - font-size: $fs12; - max-width: 75%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .list-actions { - align-items: center; - cursor: pointer; - display: none; - margin-left: auto; - - a { - svg { - fill: $color-gray-60; - height: 15px; - margin-left: $size-1; - width: 15px; - - &:hover { - fill: $color-gray-20; - } - } - } - } - - &:hover { - .list-icon { - svg { - fill: $color-primary; - } - } - - span { - color: $color-primary; - } - } - - &.selected { - .list-icon { - svg { - fill: $color-primary; - } - } - - span { - color: $color-primary; - font-weight: $fw700; - } - } - } - - &:hover { - .list-actions { - display: flex; - @include animation(0s, 0.3s, fadeIn); - } - } - } -} - -.element-set-content { - display: flex; - flex-direction: column; - padding: $size-1; - width: 100%; - - .input-text { - background-color: $color-gray-50; - border: 1px solid transparent; - border-bottom-color: $color-gray-40; - color: $color-white; - font-size: $fs12; - margin: $size-1; - min-width: 0; - padding: $size-1; - width: 100%; - - &:focus { - color: lighten($color-gray-10, 8%); - border-color: $color-primary !important; - } - - &:hover { - border-color: $color-gray-40; - } - - &.error { - border-color: $color-danger; - } - - &[disabled] { - color: $color-gray-30; - } - } - - .input-select { - /* This padding is so the text won't overlap the arrow*/ - padding-right: 1rem; - overflow: hidden; - text-overflow: ellipsis; - color: $color-gray-10; - - &:focus { - color: lighten($color-gray-10, 8%); - border-color: $color-primary; - } - - option { - color: $color-gray-60; - background: $color-white; - font-size: $fs12; - - &:disabled { - color: $color-gray-20; - } - } - } - - .input-checkbox { - label { - color: $color-gray-20; - } - - label::before { - background-color: transparent; - width: 16px; - height: 16px; - } - - label::after { - width: 16px; - height: 16px; - } - - input:checked + label::before { - border-width: 1px; - } - - input:checked + label::after { - font-size: $fs13; - } - } - - .element-set-subtitle { - color: $color-gray-20; - font-size: $fs12; - width: 64px; - - &.wide { - min-width: 75px; - } - } - - .lock-size { - cursor: pointer; - margin: auto; - - svg { - fill: $color-gray-20; - height: 14px; - width: 14px; - - &:hover { - fill: $color-primary; - } - } - - &.selected { - svg { - fill: $color-primary; - } - } - - &.disabled { - cursor: unset; - svg { - fill: $color-gray-40; - } - } - } - - .save-btn { - width: 100%; - } - - .cancel-btn { - color: $color-danger; - text-align: center; - width: 100%; - } - - .custom-select { - border: 1px solid $color-gray-40; - border-radius: $br3; - cursor: pointer; - padding: $size-1 $size-5 $size-1 $size-1; - position: relative; - - .dropdown-button { - position: absolute; - right: $size-1; - top: 7px; - - svg { - fill: $color-gray-40; - height: 10px; - width: 10px; - } - } - - span { - font-size: $fs12; - } - - &:hover { - border: 1px solid $color-gray-20; - } - - &.no-check { - .custom-select-dropdown { - width: 100%; - min-width: unset; - .check-icon { - display: none; - } - li.checked-element { - padding-left: 0.5rem; - &.is-selected { - background-color: $color-primary; - } - } - } - } - } - .opened { - border: 1px solid $color-primary; - &:hover, - &:focus { - outline: none; - border: 1px solid $color-primary; - } - } - - .custom-select-dropdown { - background-color: $color-white; - border-radius: $br3; - box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25); - left: 0; - max-height: 30rem; - min-width: 7rem; - position: absolute; - overflow-y: auto; - top: 30px; - z-index: 12; - - .presets { - width: 200px; - } - - hr { - margin: 0; - border-color: $color-gray-20; - } - - li { - color: $color-gray-60; - cursor: pointer; - font-size: $fs14; - display: flex; - gap: 0 10px; - justify-content: flex-start; - padding: $size-2; - - span { - color: $color-gray-20; - display: flex; - justify-content: flex-start; - align-items: center; - } - - .check-icon { - min-width: 25px; - color: $color-gray-20; - justify-content: center; - } - - &.dropdown-separator:not(:last-child) { - border-bottom: 1px solid $color-gray-10; - } - - &.dropdown-label:not(:first-child) { - border-top: 1px solid $color-gray-10; - } - - &.dropdown-label span { - margin-left: 0; - } - - &:hover { - background-color: $color-primary-lighter; - } - } - } - - & li.checked-element { - padding-left: 0; - - & span { - color: $color-black; - } - - & svg { - visibility: hidden; - width: 8px; - height: 8px; - background: none; - margin: 0.25rem; - fill: $color-black; - } - - &.is-selected { - & svg { - visibility: visible; - } - } - } - - .editable-select { - border: 1px solid transparent; - position: relative; - height: 38px; - // margin-left: $size-2; - max-height: 30px; - position: relative; - width: 60%; - - svg { - fill: $color-gray-10; - height: 10px; - width: 10px; - } - - .input-text { - left: 0; - position: absolute; - top: -1px; - width: 60%; - } - - input.input-text { - border: none; - background: none; - } - - .input-select { - background-color: transparent; - border: none; - border-bottom: 1px solid $color-gray-40; - color: transparent; - left: 0; - position: absolute; - top: 0; - width: 100%; - - option { - color: $color-gray-60; - background: $color-white; - font-size: $fs12; - - &:disabled { - color: $color-gray-20; - } - } - } - - .dropdown-button { - position: absolute; - right: 0; - padding-right: 4px; - height: 100%; - display: flex; - align-items: center; - } - - &.input-option { - height: 26px; - border-bottom: 1px solid #64666a; - width: 100%; - margin-left: 0.25rem; - - .input-text { - border: none; - margin: 0; - width: calc(100% - 12px); - height: 100%; - top: auto; - color: $color-white; - } - } - - .custom-select-dropdown { - top: unset; - margin-bottom: 0; - } - - &:hover { - border: 1px solid $color-gray-40; - } - } -} - -.element-set-content .border-data { - &[draggable="true"] { - cursor: pointer; - } -} - -.element-set-content .grid-option-main { - .editable-select { - height: 2rem; - } - .editable-select svg { - fill: $color-gray-40; - } - .editable-select.input-option .input-text { - padding: 0; - padding-top: 0.18rem; - padding-left: 0.25rem; - } - - .input-element { - width: 55px; - margin: 0 0.2rem; - } - - .input-text { - padding-left: 0; - color: $color-white; - background-color: transparent; - height: 30px; - } -} - -.element-set-content .component-row { - display: flex; - align-items: center; - font-size: $fs12; - color: $color-gray-10; - - svg { - fill: $color-gray-20; - height: 16px; - width: 16px; - margin-right: $size-2; - } - - .component-name { - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - } - - .row-actions { - margin-left: auto; - cursor: pointer; - - svg { - fill: $color-gray-20; - height: 12px; - margin-right: $size-1; - width: 12px; - } - - .context-menu-items { - right: 0.5rem; - left: unset; - top: 0; - - .context-menu-action { - overflow-wrap: break-word; - min-width: 223px; - white-space: break-spaces; - } - } - } - - &.copy { - flex-wrap: wrap; - border-radius: 8px; - border: 1px solid $color-gray-60; - padding: 0.5rem; - cursor: pointer; - - .component-name { - width: 80%; - color: $color-white; - } - .component-parent-name { - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - padding-left: calc(0.5rem + 16px); - color: $color-gray-40; - } - } -} - -.grid-option .custom-select { - margin-bottom: 0; -} - -.presets { - &:focus, - &:focus-within { - outline: none; - border: 1px solid $color-primary; - } - .custom-select-dropdown { - width: 237px; - - li { - font-size: $fs12; - - span { - font-size: $fs12; - } - } - } -} - -.row-flex.align-icons { - margin-left: 0; -} - -.align-icons { - cursor: pointer; - display: flex; - flex: 1; - justify-content: flex-end; - margin: $size-2 0 $size-2 $size-2; - padding: 0 $size-1; - - &:first-child { - justify-content: flex-start; - margin-left: 0; - } - - span { - align-items: center; - display: flex; - height: 20px; - justify-content: center; - margin-right: $size-2; - position: relative; - width: 20px; - - svg { - fill: $color-gray-30; - height: 14px; - width: 14px; - } - - &:hover, - &.current { - svg { - fill: $color-primary; - } - } - - &:last-child { - margin-right: 0; - } - } -} - -.element-color-picker { - align-items: center; - display: flex; - height: 100%; - justify-content: center; - margin: 0 4px; - - .color-picker-body { - height: 100%; - margin-right: 15px; - } - - .color-picker-bar { - height: 165px; - position: relative; - width: 15px; - - .color-bar-select { - background-color: $color-gray-50; - height: 3px; - left: -4px; - position: absolute; - width: 23px; - transition: none; - top: 30%; - } - } -} - -.radius-options, -.padding-options, -.margin-options { - align-items: center; - border: 1px solid $color-gray-60; - border-radius: $br4; - display: flex; - justify-content: space-between; - padding: 8px; - width: 64px; - - .radius-icon, - .padding-icon, - .margin-icon { - display: flex; - align-items: center; - - svg { - cursor: pointer; - height: 16px; - fill: $color-gray-30; - width: 16px; - } - - &:hover, - &.selected { - svg { - fill: $color-primary; - } - } - } -} - -.orientation-icon { - margin-left: $size-2; - display: flex; - align-items: center; - - svg { - cursor: pointer; - height: 20px; - fill: $color-gray-40; - width: 20px; - } - - &:hover { - svg { - fill: $color-gray-10; - } - } -} - -.navigate-icon { - background-color: $color-gray-60; - cursor: pointer; - margin-left: $size-2; - display: flex; - align-items: center; - justify-content: center; - width: 32px; - height: 32px; - - svg { - height: 16px; - fill: $color-gray-30; - width: 16px; - } - - &:hover { - svg { - stroke: $color-gray-10; - } - } -} - -.input-icon { - align-items: center; - display: flex; - width: 100%; - - &:first-child { - margin-right: $size-2; - } - - .icon-before { - align-items: center; - display: flex; - height: 18px; - position: relative; - width: 14px; - - svg { - fill: $color-gray-30; - height: 14px; - width: 14px; - } - } -} - -.custom-button { - cursor: pointer; - background: none; - border: none; - - & svg { - width: 12px; - height: 12px; - fill: $color-gray-20; - } - - &:hover svg, - &.is-active svg { - fill: $color-primary; - } -} - -.element-set-content .input-row { - & .element-set-subtitle { - width: 5.5rem; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } -} - -.grid-option, -.shadow-option { - margin-bottom: 0.5rem; - .advanced-options { - .row-flex { - justify-content: flex-end; - } - .custom-button { - left: 0; - position: absolute; - top: 12px; - } - .element-set-actions-button { - min-width: auto; - min-height: auto; - padding-right: 10px; - svg { - width: 12px; - height: 12px; - } - } - } -} - -.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, -.element-set-content .shadow-option-main { - align-items: center; - display: flex; - padding: 0.3rem 0; - border: 1px solid $color-black; - border-radius: $br4; - height: 48px; - - &:hover { - background: $color-gray-60; - - .custom-select, - .editable-select, - input { - background-color: $color-gray-50; - } - } - - & .custom-select { - min-width: 4.75rem; - height: 2rem; - border-color: transparent; - border-bottom: 1px solid #65666a; - max-height: 30px; - - &:hover { - border: 1px solid $color-gray-40; - } - } - - & .input-element { - width: 50px; - overflow: hidden; - } - - & .custom-select-dropdown { - width: 96px; - } - - & .input-option { - margin-left: 0.5rem; - - & .custom-select-dropdown { - width: 5rem; - min-width: 5rem; - max-height: 10rem; - } - } -} - -.grid-option-main-actions, -.shadow-option-main-actions { - display: flex; - visibility: hidden; - - .grid-option:hover &, - .shadow-option:hover & { - visibility: visible; - } -} - -.focus-overlay { - background: $color-black; - height: 100%; - left: 0; - position: absolute; - top: 0; - width: calc(100%); - opacity: 0.4; - z-index: 10; - display: flex; -} - -.advanced-options-wrapper { - width: 100%; -} - -.advanced-options { - border: 1px solid $color-gray-60; - background-color: $color-gray-50; - border-radius: $br4; - padding: 8px; - position: relative; - top: 2px; - width: 100%; -} - -.btn-options { - cursor: pointer; - border: 1px solid $color-black; - background: $color-gray-60; - border-radius: $br2; - color: $color-gray-20; - font-size: $fs11; - line-height: $lh-145; // Original value was 16px; 16px/11px = 145.454545455% => $lh-145 - flex-grow: 1; - padding: 0.25rem 0; - - &:first-child { - margin-right: 0.5rem; - } - - &:not([disabled]):hover { - background: $color-primary; - color: $color-black; - } - - &[disabled] { - opacity: 0.4; - cursor: auto; - } -} - -.element-set-options-group { - display: flex; - justify-content: space-between; - padding: 3px; - border: 1px solid $color-black; - border-radius: $br4; - - &:hover { - background: #1f1f1f; - } - - &.selected { - border: 1px solid $color-primary; - } - - &:not(:first-child) { - margin-top: 7px; - } - - &.open { - &:hover { - background: unset; - } - } -} - -.interactions-options { - &.element-set { - border-bottom: 0; - } - - .element-set-options-group { - flex-wrap: wrap; - } - - &:not(:first-child) { - border-top: 1px solid $color-gray-60; - } -} - -.exports-options, -.shadow-options { - .element-set-options-group { - .delete-icon { - display: flex; - min-width: 40px; - min-height: 40px; - justify-content: center; - align-items: center; - cursor: pointer; - svg { - width: 12px; - height: 12px; - fill: $color-gray-20; - } - } - } - - .download-button { - margin-top: 10px; - } - - .input-element { - width: 100%; - flex-shrink: initial; - } - - .row-grid-2 { - grid-column-gap: 1em; - } - - .color-info { - input { - margin-right: 1em; - width: 74px; - &:focus { - border-color: $color-primary !important; - color: $color-white; - outline: none; - } - - &:hover { - border-color: $color-gray-20; - } - } - } -} - -.shadow-options .color-row-wrap { - margin-left: 6px; - margin-top: 0.5rem; -} - -.element-set-actions-button { - display: flex; - min-width: 30px; - min-height: 30px; - justify-content: center; - align-items: center; - cursor: pointer; - - svg { - width: 12px; - height: 12px; - fill: $color-gray-20; - stroke: $color-gray-20; - } - - &.remove { - min-width: 20px; - min-height: 20px; - } - - &:hover svg, - &.active svg { - fill: $color-primary; - stroke: $color-primary; - } - - &.actions-inside { - position: absolute; - right: 0; - } -} - -.element-set-label { - font-size: $fs12; - padding: 0.5rem; - color: $color-gray-10; -} - -.element-set-actions { - display: flex; - visibility: hidden; -} - -.row-flex-removable:hover .element-set-actions, -.element-set-options-group:hover .element-set-actions { - visibility: visible; -} - -.layer-actions { - visibility: visible; -} - -.typography-entry { - margin: 0.5rem 0.3rem; - display: flex; - flex-direction: row; - align-items: center; - - .typography-selection-wrapper { - display: flex; - flex-direction: row; - align-items: center; - flex: 1; - height: 100%; - - &.is-selectable { - cursor: pointer; - } - } - - .typography-sample { - font-size: $fs17; - color: $color-white; - margin: 0 0.5rem; - - font-family: sourcesanspro; - font-style: normal; - font-weight: $fw400; - } - - .typography-name { - flex-grow: 1; - font-size: $fs11; - margin-top: 4px; - max-width: calc(var(--width, 256px) - 100px); - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .element-set-actions-button svg { - width: 10px; - height: 10px; - } -} - -.spacing-options { - display: flex; - width: 100%; -} - -.asset-section { - .typography-entry { - margin: 0.25rem 0; - } - - .element-set-content .font-option, - .element-set-content .size-option { - margin: 0.5rem 0; - } - .element-set-content .variant-option { - margin-left: 0.5rem; - } -} - -.row-flex input.adv-typography-name { - font-size: $fs14; - color: $color-gray-10; - width: 100%; - max-width: none; - margin: 0; - background-color: #303236; - border-top: none; - border-left: none; - border-right: none; -} - -.size-option .custom-select-dropdown { - cursor: pointer; - max-height: 16rem; - min-width: 6rem; - left: initial; - top: 0; -} - -.typography-read-only-data { - font-size: $fs12; - color: $color-white; - - .typography-name { - font-size: $fs14; - } - - .row-flex { - padding: 0.5rem 0; - } - - .label { - color: $color-gray-30; - - &::after { - content: ":"; - margin-right: 0.25rem; - } - } - - .go-to-lib-button { - color: $color-white; - transition: - border 0.3s, - color 0.3s; - text-align: center; - background: $color-gray-50; - padding: 0.5rem; - border-radius: $br2; - cursor: pointer; - font-size: $fs14; - margin-top: 1rem; - - &:hover { - background: $color-primary; - color: $color-black; - } - } -} - -.multiple-typography { - margin: 0.5rem; - padding: 0.5rem; - border: 1px dashed $color-gray-30; - border-radius: $br4; - display: flex; - justify-content: space-between; - - .multiple-typography-text, - .multiple-typography-button { - font-size: $fs12; - display: flex; - align-items: center; - } - - .multiple-typography-button { - cursor: pointer; - svg { - transition: fill 0.3s; - width: 16px; - height: 16px; - fill: $color-gray-10; - } - - &:hover svg { - fill: $color-primary; - } - } -} - -.font-selector { - background: $color-black; - height: 100%; - left: 0; - position: absolute; - top: 0; - width: calc(100%); - z-index: 10; - display: flex; - justify-content: center; - align-items: center; - - .font-selector-dropdown { - background: #303236; - display: flex; - flex-direction: column; - flex-grow: 1; - height: 100%; - } - - header { - display: flex; - flex-direction: column; - position: relative; - - .backend-filters { - padding: $size-2 $size-4; - // width: 220px; - top: 40px; - right: 20px; - } - .backend-filter { - display: flex; - align-items: center; - padding: $size-2 0; - cursor: pointer; - - .checkbox-icon { - display: flex; - justify-content: center; - align-items: center; - width: $size-4; - height: $size-4; - border: 1px solid $color-gray-30; - border-radius: $br3; - - svg { - width: 8px; - display: none; - height: 8px; - fill: $color-black; - } - } - - .backend-name { - margin-left: $size-2; - color: $color-gray-50; - } - - &.selected { - .checkbox-icon { - svg { - display: inherit; - } - } - } - } - - input { - display: flex; - flex-grow: 1; - padding: 4px; - font-size: $fs12; - background: $color-gray-50; - border-radius: $br3; - color: $color-gray-20; - border: 1px solid $color-gray-30; - width: 88%; - margin: 15px 17px; - } - - .title { - font-size: $fs14; - margin: 9px 17px; - } - - .options { - display: flex; - justify-content: center; - align-items: center; - width: 24px; - height: 24px; - margin-left: $size-2; - - svg { - width: 16px; - height: 16px; - fill: $color-gray-20; - } - - &.active { - svg { - fill: $color-primary; - } - } - } - } - - .fonts-list { - display: flex; - flex-direction: column; - height: 100%; - - position: relative; - -webkit-box-flex: 1; - flex: 1 1 auto; - } - - hr { - margin-bottom: 0px; - margin-top: 0px; - } - - .font-item { - padding-left: $size-5; - height: $size-6; - max-height: $size-6; - width: 100%; - display: flex; - align-items: center; - cursor: pointer; - color: $color-gray-10; - - &.selected { - background-color: $color-black; - color: $color-primary; - - .icon svg { - fill: $color-primary; - } - } - - &:hover { - background-color: $color-primary; - color: $color-black; - } - - .icon { - display: flex; - // justify-content: center; - align-items: center; - // border: 1px solid red; - width: $size-5; - } - - .label { - font-size: $fs12; - } - - svg { - fill: $color-gray-10; - width: 10px; - height: 10px; - } - } -} - -.row-flex.align-top { - align-items: flex-start; -} - -.constraints-widget { - min-width: 72px; - min-height: 72px; - position: relative; - background-color: $color-gray-60; - flex-grow: 0; - - .constraints-box { - width: 28px; - height: 28px; - position: absolute; - top: 22px; - left: 22px; - border: 2px solid $color-gray-50; - } - - .constraint-button { - position: absolute; - cursor: pointer; - display: flex; - justify-content: center; - align-items: center; - - &::after { - content: " "; - background-color: $color-gray-30; - } - - &.active, - &:hover { - &::after { - background-color: $color-primary; - } - } - - &.top, - &.bottom { - width: 28px; - height: 22px; - left: calc(50% - 14px); - - &::after { - width: 3px; - height: 15px; - } - } - - &.top { - top: 0; - } - - &.bottom { - bottom: 0; - } - - &.left, - &.right { - width: 22px; - height: 28px; - top: calc(50% - 14px); - - &::after { - width: 15px; - height: 3px; - } - } - - &.left { - left: 0; - } - - &.right { - right: 0; - } - - &.centerv { - width: 28px; - height: 28px; - left: calc(50% - 14px); - top: calc(50% - 14px); - - &::after { - width: 3px; - height: 15px; - } - } - - &.centerh { - width: 28px; - height: 15px; - left: calc(50% - 14px); - top: calc(50% - 7px); - - &::after { - width: 15px; - height: 3px; - } - } - } -} - -.constraints-form { - display: flex; - flex-grow: 1; - flex-direction: column; - align-items: stretch; - justify-content: flex-start; - - .input-select { - font-size: $fs12; - margin: 0 $size-1 $size-2 $size-1; - padding: 0 $size-1; - } - - svg { - width: 15px; - height: 15px; - margin-left: $size-4; - fill: $color-gray-20; - } - - .left-right svg { - transform: rotate(45deg); - } - - .top-bottom svg { - transform: rotate(-45deg); - } - - .fix-when { - font-size: $fs12; - cursor: pointer; - display: flex; - - span { - margin-left: $size-2; - } - - &:hover, - &.active { - color: $color-primary; - - svg { - fill: $color-primary; - } - } - } -} - -.cap-select { - background-color: transparent; - border: 1px solid transparent; - border-bottom-color: $color-gray-40; - color: $color-gray-10; - cursor: pointer; - font-size: $fs12; - margin: $size-1; - overflow: hidden; - padding: $size-1; - padding-right: 20px; - position: relative; - text-overflow: ellipsis; - white-space: nowrap; - width: 100%; - - & .cap-select-button { - svg { - fill: $color-gray-10; - height: 11px; - position: absolute; - right: 5px; - top: 6px; - width: 11px; - } - } - - &:hover { - border-color: $color-gray-40; - } - - &:focus { - border-color: $color-primary; - } -} - -.cap-select-dropdown { - right: 5px; - top: 30px; - z-index: 12; - width: 200px; - height: 320px; - position: fixed; - - & li.separator { - border-top: 1px solid $color-gray-10; - } - - & li img { - width: 16px; - margin-right: $size-2; - } -} - -.expand-colors { - cursor: pointer; - display: flex; - - .text { - color: $color-gray-30; - font-size: $fs12; - padding-left: 10px; - } - - svg { - width: 16px; - height: 16px; - fill: $color-gray-20; - stroke: $color-gray-20; - } -} - -.selected-colors { - .color-data { - margin-bottom: 0; - padding-bottom: 5px; - - svg { - visibility: hidden; - } - - .percentil { - margin-bottom: 0; - } - } - - .color-data:hover { - background-color: $color-gray-60; - - svg { - visibility: visible; - } - } -} - -.layout-menu, -.layout-item-menu, -.layout-grid-item-menu { - font-family: "worksans", sans-serif; - svg { - height: 16px; - width: 16px; - fill: $color-gray-30; - } - .layout-row { - display: grid; - grid-template-columns: 60px 1fr; - margin-bottom: 5px; - .row-title { - font-size: $fs12; - display: flex; - justify-content: flex-start; - align-items: center; - margin-right: 5px; - font-family: "worksans", sans-serif; - - &.justify-content, - &.align-content, - &.sizing { - align-items: flex-start; - margin-top: 4px; - } - - &.align-items-grid, - &.jusfiy-content-grid { - align-items: flex-start; - margin-top: 11px; - } - } - .btn-wrapper { - display: flex; - width: 100%; - max-width: 185px; - - &.wrap { - flex-direction: column; - gap: 5px; - } - - &.justify-content, - &.align-content { - display: flex; - flex-direction: column; - gap: 5px; - } - - .direction, - .wrap-type, - .align-items-style, - .align-self-style, - .justify-content-style, - .align-content-style, - .layout-behavior, - .absolute { - display: flex; - border-radius: $br4; - border: 1px solid $color-gray-60; - height: 26px; - margin-right: 5px; - flex-grow: 1; - &.horizontal { - button svg { - transform: rotate(90deg); - } - } - button { - display: flex; - flex-grow: 1; - justify-content: center; - align-items: center; - background: none; - border: none; - cursor: pointer; - border-right: 1px solid $color-gray-60; - color: $color-gray-20; - &.active, - &:hover { - color: $color-primary; - &.dir { - color: $color-primary; - } - svg { - fill: $color-primary; - } - } - } - .dir { - display: flex; - justify-content: center; - align-items: center; - background: none; - border: none; - cursor: pointer; - border-right: 1px solid $color-gray-60; - padding: 2px; - &.row-reverse { - svg { - transform: rotate(180deg); - } - } - - &.column-reverse { - svg { - transform: rotate(-90deg); - } - } - &.column { - svg { - transform: rotate(90deg); - } - } - &.active, - &:hover { - svg { - fill: $color-primary; - } - } - } - :last-child { - border-right: none; - } - } - .z-index { - display: flex; - align-items: center; - margin-left: 2px; - margin-top: -4px; - svg { - width: 30px; - } - } - - .edit-mode { - align-items: center; - border-radius: 4px; - border: 1px solid $color-gray-60; - display: flex; - flex-direction: row; - gap: 10px; - justify-content: center; - margin-left: 5px; - padding: 0 8px; - text-align: left; - width: 120px; - - button { - color: $color-gray-30; - display: flex; - justify-content: center; - align-items: center; - background: transparent; - border: none; - cursor: pointer; - gap: 16px; - - &.active, - &:hover { - color: $color-primary; - svg { - fill: $color-primary; - } - } - } - } - - &.align-grid-items { - flex-direction: row; - gap: 0px; - margin: 7px 0; - - .align-items-style { - margin-right: 2px; - } - } - - &.align-grid-content { - flex-direction: column; - gap: 7px; - margin: 7px 0; - } - } - .position-wrapper { - display: flex; - width: 100%; - max-width: 185px; - height: 26px; - border-radius: 4px; - border: 1px solid $color-gray-60; - - .position-btn { - display: flex; - justify-content: center; - align-items: center; - background: transparent; - border: none; - cursor: pointer; - color: $color-gray-20; - border-right: 1px solid $color-gray-60; - flex: 1; - - &:last-child { - border-right: none; - } - &.active, - &:hover { - color: $color-primary; - } - - &[disabled] { - opacity: 0.5; - &:hover { - color: $color-gray-20; - } - } - } - } - - &.single-button { - display: flex; - justify-content: flex-end; - height: 1.5rem; - - .btn-wrapper { - width: initial; - } - } - } - .no-wrap { - display: flex; - align-items: center; - justify-content: center; - height: 21px; - width: 17px; - svg { - height: 0.7rem; - width: 0.7rem; - } - } - - .wrap { - padding: 1px; - } - - .gap-group { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 7px; - margin-top: 3px; - margin-bottom: 8px; - height: 26px; - max-width: 166px; - .gap-row { - display: flex; - justify-content: center; - align-items: center; - .icon { - display: flex; - justify-content: center; - align-items: center; - margin-right: 7px; - svg { - height: 14px; - width: 14px; - } - &.rotated { - transform: rotate(90deg); - } - &.activated { - svg { - fill: $color-primary; - } - } - } - input { - font-size: $fs12; - min-width: 0; - padding: 0.25rem; - height: 20px; - margin: 0; - } - } - button { - display: flex; - justify-content: center; - align-items: center; - background: none; - border: none; - cursor: pointer; - border-radius: $br3; - - &.lock { - border: 1px solid $color-gray-60; - border-radius: $br3; - width: 30px; - height: 30px; - } - &.active { - svg { - fill: $color-primary; - } - } - &:hover { - background-color: $color-primary; - svg { - fill: $color-gray-60; - } - } - } - } - - .padding-row, - .margin-row { - display: grid; - grid-template-columns: auto 30px; - max-width: 226px; - .padding-group, - .margin-item-group { - display: flex; - margin-top: 3px; - margin-bottom: 3px; - height: 26px; - .padding-item, - .margin-item { - display: flex; - align-items: center; - flex-grow: 1; - .icon { - display: flex; - justify-content: center; - align-items: center; - margin-right: 7px; - svg { - height: 14px; - width: 14px; - } - &.rotated { - transform: rotate(90deg); - } - &.activated { - svg { - fill: $color-primary; - } - } - } - input { - font-size: $fs12; - min-width: 0; - padding: 0.25rem; - width: 70px; - height: 20px; - margin: 0; - } - } - button { - display: flex; - justify-content: center; - align-items: center; - background: none; - border: none; - cursor: pointer; - border-radius: $br3; - - &.lock { - border: 1px solid $color-gray-60; - border-radius: $br3; - width: 30px; - height: 30px; - } - &.active { - svg { - fill: $color-primary; - } - } - &:hover { - background-color: $color-primary; - svg { - fill: $color-gray-60; - } - } - } - } - .padding-icons, - .margin-item-icons { - padding: 0; - border: 1px solid $color-gray-60; - border-radius: $br3; - margin-bottom: 8px; - margin-top: $br3; - margin-right: 1px; - height: 30px; - width: 30px; - - .padding-icon, - .margin-item-icon { - display: flex; - justify-content: center; - align-items: center; - padding: 6px; - flex-grow: 1; - border-right: 1px solid $color-gray-60; - cursor: pointer; - - &:hover, - &.selected { - svg { - fill: $color-primary; - } - } - svg { - height: 14px; - width: 14px; - fill: $color-gray-30; - } - } - - :last-child { - border: none; - } - } - - .wrapper { - display: flex; - height: 26px; - - .input-element { - margin: 0; - margin-top: 3px; - height: 26px; - } - } - } - - .layout-container { - border: 1px solid $color-gray-60; - border-radius: $br3; - margin: 5px 0; - .layout-entry { - display: flex; - align-items: center; - color: $color-gray-20; - height: 38px; - cursor: pointer; - &:hover { - svg { - fill: $color-primary; - } - } - } - - .layout-info { - font-size: $fs12; - width: 100%; - overflow-x: hidden; - text-overflow: ellipsis; - white-space: nowrap; - &::first-letter { - text-transform: capitalize; - } - } - - .layout-body { - display: flex; - align-items: center; - margin: 7px; - .selects-wrapper { - width: 100%; - margin-left: 12px; - select { - text-transform: capitalize; - } - option { - text-transform: capitalize; - } - } - - .orientation-grid { - background-color: $color-gray-60; - .button-wrapper { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-template-rows: 1fr 1fr 1fr; - width: 47px; - height: 47px; - border: 1px solid $color-gray-30; - margin: 12px; - .orientation { - background: none; - border: none; - height: 14px; - width: 14px; - display: flex; - justify-content: center; - align-items: center; - padding: 2px; - cursor: pointer; - - .icon { - display: flex; - justify-content: center; - align-items: center; - svg { - fill: none; - height: 10px; - width: 10px; - } - &.rotated { - transform: rotate(90deg); - } - } - - &.active { - .icon { - svg { - fill: $color-primary; - } - } - } - &:hover { - .icon { - svg { - fill: $color-gray-20; - } - } - } - } - } - &.col { - .button-wrapper { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-template-rows: 1fr; - .orientation { - height: 100%; - justify-content: space-between; - flex-direction: column; - } - } - } - &.row { - .button-wrapper { - display: grid; - grid-template-rows: 1fr 1fr 1fr; - grid-template-columns: 1fr; - .orientation { - width: 100%; - justify-content: space-between; - padding: 2px; - } - } - } - } - } - } - - .grid-columns { - border: 1px solid $color-gray-60; - padding: 5px; - min-height: 38px; - display: flex; - flex-direction: column; - align-items: center; - &:not(:first-child) { - margin-top: 5px; - } - .grid-columns-header { - display: flex; - justify-content: center; - align-items: center; - width: 100%; - height: 100%; - flex-grow: 1; - min-height: 36px; - .columns-info { - flex-grow: 1; - font-size: 12px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - .expand-icon, - .add-column { - cursor: pointer; - background-color: transparent; - border: none; - display: flex; - justify-content: center; - align-items: center; - - &.active, - &:hover { - svg { - fill: $color-primary; - } - } - } - - .add-column svg { - height: 12px; - width: 12px; - fill: $color-gray-20; - } - } - .columns-info-wrapper { - .column-info { - display: grid; - grid-template-columns: 35px 1fr 1fr auto; - background-color: $color-gray-60; - padding: 3px; - border-radius: 3px; - border: 1px solid transparent; - - &:hover { - border: 1px solid $color-primary; - } - - &:not(:first-child) { - margin-top: 3px; - } - .direction-grid-icon { - display: flex; - justify-content: center; - align-items: center; - padding: 5px; - } - input { - background-color: $color-gray-60; - } - .grid-column-value, - .grid-column-unit { - display: flex; - justify-content: center; - align-items: center; - height: 30px; - &.active, - &:focus, - &:focus-within { - border-bottom: 1px solid $color-primary; - } - } - .grid-column-unit-selector { - border: none; - border-bottom: 1px solid $color-gray-30; - margin: 0.25rem 0; - height: 23px; - width: 100%; - &:hover { - border-bottom: 1px solid $color-gray-20; - } - } - - .remove-grid-column { - cursor: pointer; - background-color: transparent; - border: none; - display: flex; - justify-content: center; - align-items: center; - margin-left: 40px; - svg { - height: 12px; - width: 12px; - fill: $color-gray-20; - } - &.active, - &:hover { - svg { - fill: $color-primary; - } - } - } - } - } - } - .manage-grid-columns { - margin-left: 60px; - margin-bottom: 10px; - .grid-auto, - .grid-manual { - display: grid; - grid-template-columns: 1fr 1fr; - .grid-columns-auto, - .grid-rows-auto { - display: grid; - grid-template-columns: 20px 1fr; - .icon { - display: flex; - justify-content: center; - align-items: center; - } - input { - width: 80%; - } - } - } - .grid-manual { - .input-wrapper { - display: grid; - grid-template-columns: 1fr 1fr; - } - } - } -} - -.advanced-ops { - margin: 10px 0; - display: flex; - align-items: center; - cursor: pointer; - font-size: $fs12; - color: $color-gray-30; - border: none; - background-color: transparent; - padding: 0; - .icon { - display: flex; - justify-content: flex-start; - align-items: center; - margin-right: 10px; - svg { - fill: $color-gray-20; - } - } - - &:hover { - svg { - fill: $color-primary; - } - } -} -.advanced-ops-body { - .input-wrapper { - display: grid; - grid-template-columns: 1fr 1fr; - .input-element { - width: 100%; - &::after { - content: attr(alt); - width: 100px; - } - } - } -} - -.component-annotation { - background-color: $color-gray-60; - border: 1px solid $color-gray-60; - border-radius: 2px; - - .title { - display: flex; - align-items: center; - justify-content: space-between; - border-bottom: 1px solid $color-gray-50; - font-size: $fs12; - color: $color-gray-20; - padding: 0 10px; - - &.expandeable { - cursor: pointer; - } - - div { - display: flex; - align-items: center; - line-height: 2.5; - } - - .expand { - svg { - fill: $color-gray-20; - width: $size-2; - height: $size-2; - margin-right: 10px; - } - } - - .icon { - display: none; - cursor: pointer; - svg { - fill: $color-gray-20; - width: $size-4; - height: $size-4; - margin-left: 15px; - &.icon-cross { - width: $size-3; - height: $size-3; - } - } - - .icon-tick:hover, - .icon-pencil:hover { - fill: $color-primary; - } - - .icon-cross:hover, - .icon-trash:hover { - fill: $color-danger; - } - } - - &:hover { - .icon { - display: flex; - } - } - } - - &.editing { - border: 1px solid $color-primary; - .title .icon { - display: flex; - } - - textarea { - min-height: 250px; - } - } - - &.creating { - textarea { - min-height: 250px; - } - } - - .hidden { - display: none; - svg { - display: none; - } - } - - .counter { - text-align: right; - font-size: $fs11; - color: $color-gray-30; - margin: 0 10px 10px 0; - } - - // Auto growing text - .grow-wrap { - // easy way to plop the elements on top of each other and have them both sized based on the tallest one's height - display: grid; - - &:after { - // The space is needed to preventy jumpy behavior - content: attr(data-replicated-value) " "; - white-space: pre-wrap; - visibility: hidden; - } - - textarea { - background-color: $color-gray-60; - color: $color-white; - padding: 10px; - - border: none; - overflow: hidden; - outline: none; - - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; - - resize: none; /*remove the resize handle on the bottom right*/ - } - - textarea, - &:after { - /* Identical styling required!! */ - font: inherit; - font-size: $fs14; - overflow-wrap: anywhere; - - padding: 10px; - - /* Place on top of each other */ - grid-area: 1 / 1 / 2 / 2; - } - } -} - -.component-block-title { - border: none; - background: none; - - svg { - height: 8px; - width: 8px; - fill: $color-gray-20; - margin-right: 1rem; - transform: rotate(180deg); - } - - &.back { - cursor: pointer; - } -} diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index c4e1f8b3e2..4972589ed6 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -20,7 +20,6 @@ [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.select :refer [select]] [app.main.ui.components.tab-container :refer [tab-container tab-element]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.colorpicker.color-inputs :refer [color-inputs]] [app.main.ui.workspace.colorpicker.gradients :refer [gradients]] @@ -52,8 +51,7 @@ (mf/defc colorpicker [{:keys [data disable-gradient disable-opacity disable-image on-change on-accept]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - state (mf/deref refs/colorpicker) + (let [state (mf/deref refs/colorpicker) node-ref (mf/use-ref) ;; TODO: I think we need to put all this picking state under @@ -267,235 +265,123 @@ :h h :s s :v v :alpha (/ alpha 255)})))) - (if new-css-system - [:div {:class (stl/css :colorpicker) - :ref node-ref - :style {:touch-action "none"}} - [:div {:class (stl/css :top-actions)} - (when (or (not disable-gradient) (not disable-image)) - [:div {:class (stl/css :select)} - [:& select - {:default-value selected-mode - :options options - :on-change handle-change-mode}]]) - (when (not= selected-mode :image) - [:button {:class (stl/css-case :picker-btn true - :selected picking-color?) - :on-click handle-click-picker} - i/picker-refactor])] + [:div {:class (stl/css :colorpicker) + :ref node-ref + :style {:touch-action "none"}} + [:div {:class (stl/css :top-actions)} + (when (or (not disable-gradient) (not disable-image)) + [:div {:class (stl/css :select)} + [:& select + {:default-value selected-mode + :options options + :on-change handle-change-mode}]]) + (when (not= selected-mode :image) + [:button {:class (stl/css-case :picker-btn true + :selected picking-color?) + :on-click handle-click-picker} + i/picker-refactor])] - (when (or (= selected-mode :linear-gradient) + (when (or (= selected-mode :linear-gradient) (= selected-mode :radial-gradient)) - [:& gradients - {:stops (:stops state) - :editing-stop (:editing-stop state) - :on-select-stop handle-change-stop}]) + [:& gradients + {:stops (:stops state) + :editing-stop (:editing-stop state) + :on-select-stop handle-change-stop}]) - (if (= selected-mode :image) - (let [uri (cfg/resolve-file-media (:image current-color))] - [:div {:class (stl/css :select-image)} - [:div {:class (stl/css :content)} - (when (:image current-color) - [:img {:src uri}])] - [:button - {:class (stl/css :choose-image) - :title (tr "media.choose-image") - :aria-label (tr "media.choose-image") - :on-click on-fill-image-click} - (tr "media.choose-image") - [:& file-uploader - {:input-id "fill-image-upload" - :accept "image/jpeg,image/png" - :multi false - :ref fill-image-ref - :on-selected on-fill-image-selected}]]]) - [:* - [:div {:class (stl/css :colorpicker-tabs)} - [:& tab-container - {:on-change-tab set-tab! - :selected @active-color-tab - :collapsable? false} - - [:& tab-element {:id :ramp :title i/rgba-refactor} - (if picking-color? - [:div {:class (stl/css :picker-detail-wrapper)} - [:div {:class (stl/css :center-circle)}] - [:canvas#picker-detail {:width 256 :height 140}]] - [:& ramp-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])] - - [:& tab-element {:id :harmony :title i/rgba-complementary-refactor} - (if picking-color? - [:div {:class (stl/css :picker-detail-wrapper)} - [:div {:class (stl/css :center-circle)}] - [:canvas#picker-detail {:width 256 :height 140}]] - [:& harmony-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])] - - [:& tab-element {:id :hsva :title i/hsva-refactor} - (if picking-color? - [:div {:class (stl/css :picker-detail-wrapper)} - [:div {:class (stl/css :center-circle)}] - [:canvas#picker-detail {:width 256 :height 140}]] - [:& hsva-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])]]] - - [:& color-inputs - {:type (if (= @active-color-tab :hsva) :hsv :rgb) - :disable-opacity disable-opacity - :color current-color - :on-change handle-change-color}] - - [:& libraries - {:state state - :current-color current-color - :disable-gradient disable-gradient - :disable-opacity disable-opacity - :disable-image disable-image - :on-select-color on-select-library-color - :on-add-library-color on-add-library-color}]]) - - (when on-accept - [:div {:class (stl/css :actions)} - [:button {:class (stl/css-case - :accept-color true - :btn-disabled disabled-color-accept?) - :on-click on-color-accept - :disabled disabled-color-accept?} - (tr "workspace.libraries.colors.save-color")]])] - - [:div.colorpicker {:ref node-ref - :style {:touch-action "none"}} - [:div.colorpicker-content - [:div.top-actions - (when (or (not disable-gradient) (not disable-image)) - [:div.element-set-content - [:& select - {:default-value selected-mode - :options options - :on-change handle-change-mode}]]) - (when (not= selected-mode :image) - [:button.picker-btn - {:class (when picking-color? "active") - :on-click handle-click-picker} - i/picker])] - - (when (or (= (:type state) :linear-gradient) - (= (:type state) :radial-gradient)) - - [:& gradients - {:stops (:stops state) - :editing-stop (:editing-stop state) - :on-select-stop handle-change-stop}]) - - (if (= selected-mode :image) - (let [uri (cfg/resolve-file-media (:image current-color))] - [:div.select-image - [:div.content - (when (:image current-color) - [:img {:src uri}])] - [:button.btn-secondary - {:title (tr "media.choose-image") - :aria-label (tr "media.choose-image") - :on-click on-fill-image-click} - (tr "media.choose-image") - [:& file-uploader - {:input-id "fill-image-upload" - :accept "image/jpeg,image/png" - :multi false - :ref fill-image-ref - :on-selected on-fill-image-selected}]]]) - [:* - [:div.colorpicker-tabs - [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand - {:class (when (= @active-color-tab :ramp) "active") - :alt (tr "workspace.libraries.colors.rgba") - :on-click set-tab! - :data-tab "ramp"} i/picker-ramp] - [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand - {:class (when (= @active-color-tab :harmony) "active") - :alt (tr "workspace.libraries.colors.rgb-complementary") - :on-click set-tab! - :data-tab "harmony"} i/picker-harmony] - [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand - {:class (when (= @active-color-tab :hsva) "active") - :alt (tr "workspace.libraries.colors.hsv") - :on-click set-tab! - :data-tab "hsva"} i/picker-hsv]] + (if (= selected-mode :image) + (let [uri (cfg/resolve-file-media (:image current-color))] + [:div {:class (stl/css :select-image)} + [:div {:class (stl/css :content)} + (when (:image current-color) + [:img {:src uri}])] + [:button + {:class (stl/css :choose-image) + :title (tr "media.choose-image") + :aria-label (tr "media.choose-image") + :on-click on-fill-image-click} + (tr "media.choose-image") + [:& file-uploader + {:input-id "fill-image-upload" + :accept "image/jpeg,image/png" + :multi false + :ref fill-image-ref + :on-selected on-fill-image-selected}]]]) + [:* + [:div {:class (stl/css :colorpicker-tabs)} + [:& tab-container + {:on-change-tab set-tab! + :selected @active-color-tab + :collapsable? false} + [:& tab-element {:id :ramp :title i/rgba-refactor} (if picking-color? - [:div.picker-detail-wrapper - [:div.center-circle] - [:canvas#picker-detail {:width 200 :height 160}]] - (case @active-color-tab - :ramp - [:& ramp-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - :harmony - [:& harmony-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - :hsva - [:& hsva-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - nil)) + [:div {:class (stl/css :picker-detail-wrapper)} + [:div {:class (stl/css :center-circle)}] + [:canvas#picker-detail {:width 256 :height 140}]] + [:& ramp-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])] - [:& color-inputs - {:type (if (= @active-color-tab :hsva) :hsv :rgb) - :disable-opacity disable-opacity - :color current-color - :on-change handle-change-color}] + [:& tab-element {:id :harmony :title i/rgba-complementary-refactor} + (if picking-color? + [:div {:class (stl/css :picker-detail-wrapper)} + [:div {:class (stl/css :center-circle)}] + [:canvas#picker-detail {:width 256 :height 140}]] + [:& harmony-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])] - [:& libraries - {:state state - :current-color current-color - :disable-gradient disable-gradient - :disable-opacity disable-opacity - :disable-image disable-image - :on-select-color on-select-library-color - :on-add-library-color on-add-library-color}]]) + [:& tab-element {:id :hsva :title i/hsva-refactor} + (if picking-color? + [:div {:class (stl/css :picker-detail-wrapper)} + [:div {:class (stl/css :center-circle)}] + [:canvas#picker-detail {:width 256 :height 140}]] + [:& hsva-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])]]] - (when on-accept - [:div.actions - [:button.btn-primary.btn-large - {:on-click on-color-accept - :disabled disabled-color-accept? - :class (dom/classnames - :btn-disabled disabled-color-accept?)} - (tr "workspace.libraries.colors.save-color")]])]]))) + [:& color-inputs + {:type (if (= @active-color-tab :hsva) :hsv :rgb) + :disable-opacity disable-opacity + :color current-color + :on-change handle-change-color}] + + [:& libraries + {:state state + :current-color current-color + :disable-gradient disable-gradient + :disable-opacity disable-opacity + :disable-image disable-image + :on-select-color on-select-library-color + :on-add-library-color on-add-library-color}]]) + + (when on-accept + [:div {:class (stl/css :actions)} + [:button {:class (stl/css-case + :accept-color true + :btn-disabled disabled-color-accept?) + :on-click on-color-accept + :disabled disabled-color-accept?} + (tr "workspace.libraries.colors.save-color")]])])) (defn calculate-position "Calculates the style properties for the given coordinates and position" - [{vh :height} position x y new-css-system] + [{vh :height} position x y] (let [;; picker height in pixels - h(if new-css-system 510 430) + h 510 ;; Checks for overflow outside the viewport height overflow-fix (max 0 (+ y (- 50) h (- vh))) - x-pos (if new-css-system 325 250)] + x-pos 325] (cond (or (nil? x) (nil? y)) {:left "auto" :right "16rem" :top "4rem"} (= position :left) {:left (str (- x x-pos) "px") @@ -512,12 +398,11 @@ disable-opacity disable-image on-change on-close on-accept] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - vport (mf/deref viewport) + (let [vport (mf/deref viewport) dirty? (mf/use-var false) last-change (mf/use-var nil) position (or position :left) - style (calculate-position vport position x y new-css-system) + style (calculate-position vport position x y) handle-change (fn [new-data] @@ -531,7 +416,7 @@ #(when (and @dirty? @last-change on-close) (on-close @last-change)))) - [:div {:class (stl/css new-css-system :colorpicker-tooltip) + [:div {:class (stl/css :colorpicker-tooltip) :style (clj->js style)} [:& colorpicker {:data data :disable-gradient disable-gradient diff --git a/frontend/src/app/main/ui/workspace/colorpicker.scss b/frontend/src/app/main/ui/workspace/colorpicker.scss index ae18f6abd6..4abe58b463 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.scss +++ b/frontend/src/app/main/ui/workspace/colorpicker.scss @@ -11,118 +11,126 @@ top: $s-100; left: calc(10 * $s-140); width: auto; - .colorpicker { - border-radius: $br-8; - width: $s-260; - & > * { - width: $s-260; - } - .top-actions { - display: flex; - align-items: flex-start; - flex-direction: row-reverse; - justify-content: space-between; - height: $s-40; - .picker-btn { - @include buttonStyle; - @include flexCenter; - border-radius: $br-8; - background-color: transparent; - border: $s-1 solid transparent; - height: $s-20; - width: $s-20; - border-radius: $br-4; - padding: 0; - margin-top: $s-4; - svg { - @extend .button-icon; - stroke: var(--button-tertiary-foreground-color-rest); - } - &:hover { - svg { - stroke: var(--button-tertiary-foreground-color-focus); - } - } - &:focus, - &:focus-visible { - outline: none; - svg { - stroke: var(--button-secondary-foreground-color-hover); - } - } - &:active { - outline: none; - border: $s-1 solid transparent; - svg { - stroke: var(--button-tertiary-foreground-color-active); - } - } - &.selected { - svg { - stroke: var(--button-tertiary-foreground-color-active); - } - } - } - .gradient-buttons { - display: flex; - align-items: center; - gap: $s-8; - .gradient-btn { - @extend .button-tertiary; - height: $s-20; - width: $s-20; - border-radius: $br-4; - border: $s-2 solid transparent; - &:hover { - border: $s-2 solid var(--colorpicker-details-color-selected); - } - } - .linear-gradient-btn { - background: linear-gradient(180deg, var(--color-foreground-secondary), transparent); - &.selected { - background: linear-gradient(to bottom, rgba(126, 255, 245, 1) 0%, rgba(126, 255, 245, 0.2) 100%); - border: $s-2 solid var(--colorpicker-details-color-selected); - } - } +} - .radial-gradient-btn { - background: radial-gradient(transparent, var(--color-foreground-secondary)); - &.selected { - background: radial-gradient(rgba(126, 255, 245, 1) 0%, rgba(126, 255, 245, 0.2) 100%); - border: $s-2 solid var(--colorpicker-details-color-selected); - } - } - } - } - .actions { - display: flex; - gap: $s-4; - .accept-color { - @include tabTitleTipography; - @extend .button-secondary; - width: 100%; - height: $s-32; - margin-top: $s-8; - } +.colorpicker { + border-radius: $br-8; + width: $s-260; + & > * { + width: $s-260; + } +} + +.top-actions { + display: flex; + align-items: flex-start; + flex-direction: row-reverse; + justify-content: space-between; + height: $s-40; +} + +.picker-btn { + @include buttonStyle; + @include flexCenter; + border-radius: $br-8; + background-color: transparent; + border: $s-1 solid transparent; + height: $s-20; + width: $s-20; + border-radius: $br-4; + padding: 0; + margin-top: $s-4; + svg { + @extend .button-icon; + stroke: var(--button-tertiary-foreground-color-rest); + } + &:hover { + svg { + stroke: var(--button-tertiary-foreground-color-focus); } } - .colorpicker-tabs { - .picker-detail-wrapper { - @include flexCenter; - position: relative; - margin: $s-12 0 $s-8 0; - .center-circle { - width: $s-24; - height: $s-24; - border: $s-2 solid var(--colorpicker-details-color); - border-radius: $br-circle; - position: absolute; - left: 50%; - top: 50%; - transform: translate(calc(-1 * $s-12), calc(-1 * $s-12)); - } + &:focus, + &:focus-visible { + outline: none; + svg { + stroke: var(--button-secondary-foreground-color-hover); } } + &:active { + outline: none; + border: $s-1 solid transparent; + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } + &.selected { + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } +} + +.gradient-buttons { + display: flex; + align-items: center; + gap: $s-8; +} + +.gradient-btn { + @extend .button-tertiary; + height: $s-20; + width: $s-20; + border-radius: $br-4; + border: $s-2 solid transparent; + &:hover { + border: $s-2 solid var(--colorpicker-details-color-selected); + } +} + +.linear-gradient-btn { + background: linear-gradient(180deg, var(--color-foreground-secondary), transparent); + &.selected { + background: linear-gradient(to bottom, rgba(126, 255, 245, 1) 0%, rgba(126, 255, 245, 0.2) 100%); + border: $s-2 solid var(--colorpicker-details-color-selected); + } +} + +.radial-gradient-btn { + background: radial-gradient(transparent, var(--color-foreground-secondary)); + &.selected { + background: radial-gradient(rgba(126, 255, 245, 1) 0%, rgba(126, 255, 245, 0.2) 100%); + border: $s-2 solid var(--colorpicker-details-color-selected); + } +} + +.actions { + display: flex; + gap: $s-4; +} + +.accept-color { + @include tabTitleTipography; + @extend .button-secondary; + width: 100%; + height: $s-32; + margin-top: $s-8; +} + +.picker-detail-wrapper { + @include flexCenter; + position: relative; + margin: $s-12 0 $s-8 0; +} + +.center-circle { + width: $s-24; + height: $s-24; + border: $s-2 solid var(--colorpicker-details-color); + border-radius: $br-circle; + position: absolute; + left: 50%; + top: 50%; + transform: translate(calc(-1 * $s-12), calc(-1 * $s-12)); } .select { @@ -131,29 +139,31 @@ .select-image { margin-top: $s-4; - .content { - border-radius: $br-8; - display: flex; - justify-content: center; - background-image: url("/images/colorpicker-no-image.png"); - background-position: center; - background-size: auto $s-140; - height: $s-140; - margin-bottom: $s-6; - margin-right: $s-1; - img { - height: fit-content; - width: fit-content; - max-height: 100%; - max-width: 100%; - margin: auto; - } - } - .choose-image { - @extend .button-secondary; - @include tabTitleTipography; - width: 100%; - margin-top: $s-12; - height: $s-32; +} + +.content { + border-radius: $br-8; + display: flex; + justify-content: center; + background-image: url("/images/colorpicker-no-image.png"); + background-position: center; + background-size: auto $s-140; + height: $s-140; + margin-bottom: $s-6; + margin-right: $s-1; + img { + height: fit-content; + width: fit-content; + max-height: 100%; + max-width: 100%; + margin: auto; } } + +.choose-image { + @extend .button-secondary; + @include tabTitleTipography; + width: 100%; + margin-top: $s-12; + height: $s-32; +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs index 4242861de6..9764b4eaec 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs @@ -8,7 +8,6 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] - [app.main.ui.context :as ctx] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -22,40 +21,22 @@ (mf/defc gradients [{:keys [stops editing-stop on-select-stop]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :gradient-stops)} - [:div {:class (stl/css :gradient-background-wrapper)} - [:div {:class (stl/css :gradient-background) - :style {:background (gradient->string stops)}}]] + [:div {:class (stl/css :gradient-stops)} + [:div {:class (stl/css :gradient-background-wrapper)} + [:div {:class (stl/css :gradient-background) + :style {:background (gradient->string stops)}}]] - [:div {:class (stl/css :gradient-stop-wrapper)} - (for [{:keys [offset hex r g b alpha] :as value} stops] - [:button {:class (stl/css-case :gradient-stop true - :selected (= editing-stop offset)) - :data-value offset - :on-click on-select-stop - :style {:left (dm/str (* offset 100) "%") - :backgroundColor hex} - :key (dm/str offset)} + [:div {:class (stl/css :gradient-stop-wrapper)} + (for [{:keys [offset hex r g b alpha] :as value} stops] + [:button {:class (stl/css-case :gradient-stop true + :selected (= editing-stop offset)) + :data-value offset + :on-click on-select-stop + :style {:left (dm/str (* offset 100) "%") + :backgroundColor hex} + :key (dm/str offset)} - [:div {:class (stl/css :gradient-stop-color) - :style {:background-color hex}}] - [:div {:class (stl/css :gradient-stop-alpha) - :style {:background-color (str/ffmt "rgba(%1, %2, %3, %4)" r g b alpha)}}]])]] - - [:div.gradient-stops - [:div.gradient-background-wrapper - [:div.gradient-background {:style {:background (gradient->string stops)}}]] - - [:div.gradient-stop-wrapper - (for [{:keys [offset hex r g b alpha] :as value} stops] - [:div.gradient-stop - {:class (when (= editing-stop offset) "active") - :data-value offset - :on-click on-select-stop - :style {:left (dm/str (* offset 100) "%")} - :key (dm/str offset)} - - [:div.gradient-stop-color {:style {:background-color hex}}] - [:div.gradient-stop-alpha {:style {:background-color (str/ffmt "rgba(%1, %2, %3, %4)" r g b alpha)}}]])]]))) + [:div {:class (stl/css :gradient-stop-color) + :style {:background-color hex}}] + [:div {:class (stl/css :gradient-stop-alpha) + :style {:background-color (str/ffmt "rgba(%1, %2, %3, %4)" r g b alpha)}}]])]]) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.scss b/frontend/src/app/main/ui/workspace/colorpicker/gradients.scss index 78932650dd..a9b4107eeb 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/gradients.scss +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.scss @@ -13,39 +13,41 @@ margin: $s-12 0; background-color: var(--colorpicker-handlers-color); border-radius: $br-6; +} - .gradient-background-wrapper { - height: 100%; - width: 100%; - border-radius: $br-6; - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") - left center; +.gradient-background-wrapper { + height: 100%; + width: 100%; + border-radius: $br-6; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") + left center; +} - .gradient-background { - height: 100%; - width: 100%; - border-radius: $br-6; - border: $s-2 solid var(--colorpicker-details-color); - } - } - .gradient-stop-wrapper { - position: absolute; - width: calc(100% - 2rem); - .gradient-stop { - position: absolute; - display: grid; - grid-template-columns: 50% 50%; - width: $s-16; - height: $s-24; - border-radius: $br-4; - margin-top: calc(-1 * $s-2); - margin-left: calc(-1 * $s-8); - border: $s-2 solid var(--colorpicker-handlers-color); - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") - left center; - &.selected { - border: $s-2 solid var(--colorpicker-details-color-selected); - } - } +.gradient-background { + height: 100%; + width: 100%; + border-radius: $br-6; + border: $s-2 solid var(--colorpicker-details-color); +} + +.gradient-stop-wrapper { + position: absolute; + width: calc(100% - 2rem); +} + +.gradient-stop { + position: absolute; + display: grid; + grid-template-columns: 50% 50%; + width: $s-16; + height: $s-24; + border-radius: $br-4; + margin-top: calc(-1 * $s-2); + margin-left: calc(-1 * $s-8); + border: $s-2 solid var(--colorpicker-handlers-color); + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") + left center; + &.selected { + border: $s-2 solid var(--colorpicker-details-color-selected); } } diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs index 2bc19b28bc..7ca720bd2a 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs @@ -10,7 +10,6 @@ [app.common.colors :as cc] [app.common.geom.point :as gpt] [app.common.math :as mth] - [app.main.ui.context :as ctx] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.dom :as dom] [app.util.object :as obj] @@ -59,11 +58,8 @@ (gpt/point x y))) (mf/defc harmony-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - canvas-ref (mf/use-ref nil) - canvas-side (if new-css-system - 192 - 152) + (let [canvas-ref (mf/use-ref nil) + canvas-side 192 {hue :h saturation :s value :v alpha :alpha} color pos-current (color->point canvas-side hue saturation) @@ -128,83 +124,44 @@ (mf/deps canvas-ref) (fn [] (when canvas-ref (create-color-wheel (mf/ref-val canvas-ref))))) - (if new-css-system - [:div {:class (stl/css :harmony-selector)} - [:div {:class (stl/css :handlers-wrapper)} - [:& slider-selector {:type :value - :vertical? true - :reverse? true - :value value - :max-value 255 - :vertical true - :on-change on-change-value - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - (when (not disable-opacity) - [[:& slider-selector {:type :opacity - :vertical? true - :value alpha - :max-value 1 - :vertical true - :on-change on-change-opacity - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}]])] + [:div {:class (stl/css :harmony-selector)} + [:div {:class (stl/css :handlers-wrapper)} + [:& slider-selector {:type :value + :vertical? true + :reverse? true + :value value + :max-value 255 + :vertical true + :on-change on-change-value + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + (when (not disable-opacity) + [[:& slider-selector {:type :opacity + :vertical? true + :value alpha + :max-value 1 + :vertical true + :on-change on-change-opacity + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]])] - [:div {:class (stl/css :hue-wheel-wrapper)} - [:canvas {:class (stl/css :hue-wheel) - :ref canvas-ref - :width canvas-side - :height canvas-side - :on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))}] - [:div {:class (stl/css :handler) - :style {:pointer-events "none" - :left (:x pos-current) - :top (:y pos-current)}}] - [:div {:class (stl/css-case :handler true - :complement true) - :style {:left (:x pos-complement) - :top (:y pos-complement) - :cursor "pointer"} - :on-click on-complement-click}]]] - - [:div.harmony-selector - [:div.hue-wheel-wrapper - [:canvas.hue-wheel - {:ref canvas-ref - :width canvas-side - :height canvas-side - :on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))}] - [:div.handler {:style {:pointer-events "none" - :left (:x pos-current) - :top (:y pos-current)}}] - [:div.handler.complement {:style {:left (:x pos-complement) - :top (:y pos-complement) - :cursor "pointer"} - :on-click on-complement-click}]] - [:div.handlers-wrapper - [:& slider-selector {:class "value" - :vertical? true - :reverse? true - :value value - :max-value 255 - :vertical true - :on-change on-change-value - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - (when (not disable-opacity) - [:& slider-selector {:class "opacity" - :vertical? true - :value alpha - :max-value 1 - :vertical true - :on-change on-change-opacity - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])]]))) + [:div {:class (stl/css :hue-wheel-wrapper)} + [:canvas {:class (stl/css :hue-wheel) + :ref canvas-ref + :width canvas-side + :height canvas-side + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))}] + [:div {:class (stl/css :handler) + :style {:pointer-events "none" + :left (:x pos-current) + :top (:y pos-current)}}] + [:div {:class (stl/css-case :handler true + :complement true) + :style {:left (:x pos-complement) + :top (:y pos-complement) + :cursor "pointer"} + :on-click on-complement-click}]]])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.scss b/frontend/src/app/main/ui/workspace/colorpicker/harmony.scss index 15b9f54d5e..04bc1d46ac 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/harmony.scss +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.scss @@ -12,32 +12,33 @@ gap: $s-8; margin-top: $s-12; margin-bottom: $s-8; - .hue-wheel-wrapper { - @include flexCenter; - position: relative; - - .hue-wheel { - width: $s-196; - height: $s-196; - } - - .handler { - @extend .colorpicker-handler; - height: $s-16; - width: $s-16; - border: $s-2 solid var(--colorpicker-handlers-color); - } - - .handler.complement { - background-color: var(--colorpicker-handlers-color); - border: $s-2 solid var(--colorpicker-handlers-color); - } - } - - .handlers-wrapper { - @include flexRow; - height: $s-200; - width: $s-52; - flex-grow: 1; - } +} + +.hue-wheel-wrapper { + @include flexCenter; + position: relative; +} + +.hue-wheel { + width: $s-196; + height: $s-196; +} + +.handler { + @extend .colorpicker-handler; + height: $s-16; + width: $s-16; + border: $s-2 solid var(--colorpicker-handlers-color); +} + +.handler.complement { + background-color: var(--colorpicker-handlers-color); + border: $s-2 solid var(--colorpicker-handlers-color); +} + +.handlers-wrapper { + @include flexRow; + height: $s-200; + width: $s-52; + flex-grow: 1; } diff --git a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs index 9236371144..cf4554b6e3 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs @@ -8,13 +8,11 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as cc] - [app.main.ui.context :as ctx] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [rumext.v2 :as mf])) (mf/defc hsva-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - {hue :h saturation :s value :v alpha :alpha} color + (let [{hue :h saturation :s value :v alpha :alpha} color handle-change-slider (fn [key] (fn [new-value] (let [change (hash-map key new-value) @@ -25,87 +23,46 @@ {:hex hex :r r :g g :b b}))))) on-change-opacity (fn [new-alpha] (on-change {:alpha new-alpha}))] - (if new-css-system - [:div {:class (stl/css :hsva-selector)} + [:div {:class (stl/css :hsva-selector)} + [:div {:class (stl/css :hsva-row)} + [:span {:class (stl/css :hsva-selector-label)} "H"] + [:& slider-selector + {:class (stl/css :hsva-bar) + :type :hue + :max-value 360 + :value hue + :on-change (handle-change-slider :h) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]] + [:div {:class (stl/css :hsva-row)} + [:span {:class (stl/css :hsva-selector-label)} "S"] + [:& slider-selector + {:class (stl/css :hsva-bar) + :type :saturation + :max-value 1 + :value saturation + :on-change (handle-change-slider :s) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]] + [:div {:class (stl/css :hsva-row)} + [:span {:class (stl/css :hsva-selector-label)} "V"] + [:& slider-selector + {:class (stl/css :hsva-bar) + :type :value + :reverse? false + :max-value 255 + :value value + :on-change (handle-change-slider :v) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]] + (when (not disable-opacity) [:div {:class (stl/css :hsva-row)} - [:span {:class (stl/css :hsva-selector-label)} "H"] + [:span {:class (stl/css :hsva-selector-label)} "A"] [:& slider-selector {:class (stl/css :hsva-bar) - :type :hue - :max-value 360 - :value hue - :on-change (handle-change-slider :h) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}]] - [:div {:class (stl/css :hsva-row)} - [:span {:class (stl/css :hsva-selector-label)} "S"] - [:& slider-selector - {:class (stl/css :hsva-bar) - :type :saturation + :type :opacity :max-value 1 - :value saturation - :on-change (handle-change-slider :s) + :value alpha + :on-change on-change-opacity :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}]] - [:div {:class (stl/css :hsva-row)} - [:span {:class (stl/css :hsva-selector-label)} "V"] - [:& slider-selector - {:class (stl/css :hsva-bar) - :type :value - :reverse? false - :max-value 255 - :value value - :on-change (handle-change-slider :v) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}]] - (when (not disable-opacity) - [:div {:class (stl/css :hsva-row)} - [:span {:class (stl/css :hsva-selector-label)} "A"] - [:& slider-selector - {:class (stl/css :hsva-bar) - :type :opacity - :max-value 1 - :value alpha - :on-change on-change-opacity - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}]])] - - [:div.hsva-selector - [:span.hsva-selector-label "H"] - [:& slider-selector - {:class "hue" - :max-value 360 - :value hue - :on-change (handle-change-slider :h) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - [:span.hsva-selector-label "S"] - [:& slider-selector - {:class "saturation" - :max-value 1 - :value saturation - :on-change (handle-change-slider :s) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - [:span.hsva-selector-label "V"] - [:& slider-selector - {:class "value" - :reverse? false - :max-value 255 - :value value - :on-change (handle-change-slider :v) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - (when (not disable-opacity) - [:* - [:span.hsva-selector-label "A"] - [:& slider-selector - {:class "opacity" - :max-value 1 - :value alpha - :on-change on-change-opacity - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}]])]) - )) + :on-finish-drag on-finish-drag}]])])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/hsva.scss b/frontend/src/app/main/ui/workspace/colorpicker/hsva.scss index 03e2d66b68..be13a492b5 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/hsva.scss +++ b/frontend/src/app/main/ui/workspace/colorpicker/hsva.scss @@ -11,18 +11,21 @@ padding: $s-4; grid-row-gap: $s-8; margin-bottom: $s-8; - .hsva-row { - display: flex; - align-items: center; - .hsva-selector-label { - @include tabTitleTipography; - display: flex; - align-items: center; - justify-content: flex-start; - width: $s-32; - } - .hsva-bar { - width: $s-228; - } - } +} + +.hsva-row { + display: flex; + align-items: center; +} + +.hsva-selector-label { + @include tabTitleTipography; + display: flex; + align-items: center; + justify-content: flex-start; + width: $s-32; +} + +.hsva-bar { + width: $s-228; } diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index d184ba8b4e..5970835a0b 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -14,10 +14,8 @@ [app.main.data.workspace.colors :as mdc] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.color-bullet :refer [color-bullet]] [app.main.ui.components.color-bullet-new :as cb] [app.main.ui.components.select :refer [select]] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.hooks.resize :as r] [app.main.ui.icons :as i] @@ -28,8 +26,7 @@ (mf/defc libraries [{:keys [state on-select-color on-add-library-color disable-gradient disable-opacity disable-image]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - selected (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent) + (let [selected (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent) current-colors (mf/use-state []) shared-libs (mf/deref refs/workspace-libraries) @@ -40,14 +37,11 @@ on-library-change (mf/use-fn (fn [event] - (let [val (if new-css-system - event - (dom/get-target-val event))] - (reset! selected - (if (or (= val "recent") - (= val "file")) - (keyword val) - (parse-uuid val)))))) + (reset! selected + (if (or (= event "recent") + (= event "file")) + (keyword event) + (parse-uuid event))))) check-valid-color? (fn [color] @@ -103,59 +97,26 @@ (let [colors (vals file-colors)] (reset! current-colors (into [] (filter check-valid-color?) colors))))) - (if new-css-system - [:div {:class (stl/css :libraries)} - [:div {:class (stl/css :select-wrapper)} - [:& select - {:class (stl/css :shadow-type-select) - :default-value (or (name @selected) "recent") - :options options - :on-change on-library-change}]] + [:div {:class (stl/css :libraries)} + [:div {:class (stl/css :select-wrapper)} + [:& select + {:class (stl/css :shadow-type-select) + :default-value (or (name @selected) "recent") + :options options + :on-change on-library-change}]] - [:div {:class (stl/css :selected-colors)} - (when (= @selected :file) - [:button {:class (stl/css :add-color-btn) - :on-click on-add-library-color} - i/add-refactor]) + [:div {:class (stl/css :selected-colors)} + (when (= @selected :file) + [:button {:class (stl/css :add-color-btn) + :on-click on-add-library-color} + i/add-refactor]) - [:button {:class (stl/css :palette-btn) - :on-click toggle-palette} - i/swatches-refactor] + [:button {:class (stl/css :palette-btn) + :on-click toggle-palette} + i/swatches-refactor] - (for [[idx color] (map-indexed vector @current-colors)] - [:& cb/color-bullet - {:key (dm/str "color-" idx) - :color color - :on-click on-color-click}])]] - - - [:div.libraries - [:select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :on-change on-library-change - :value (name @selected)} - [:option {:value "recent"} (tr "workspace.libraries.colors.recent-colors")] - [:option {:value "file"} (tr "workspace.libraries.colors.file-library")] - - (for [[_ {:keys [name id]}] shared-libs] - [:option {:key id :value id} name])] - - [:div.selected-colors - (when (= @selected :file) - [:div.color-bullet.button.plus-button {:style {:background-color "var(--color-white)"} - :on-click on-add-library-color} - i/plus]) - - [:div.color-bullet.button {:style {:background-color "var(--color-white)"} - :on-click (fn [] - (r/set-resize-type! :bottom) - (dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down") - (ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette) - (-> (dw/toggle-layout-flag :colorpalette) - (vary-meta assoc ::ev/origin "workspace-colorpicker")))))} - i/palette] - - (for [[idx color] (map-indexed vector @current-colors)] - [:& color-bullet - {:key (dm/str "color-" idx) - :color color - :on-click on-color-click}])]]))) + (for [[idx color] (map-indexed vector @current-colors)] + [:& cb/color-bullet + {:key (dm/str "color-" idx) + :color color + :on-click on-color-click}])]])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.scss b/frontend/src/app/main/ui/workspace/colorpicker/libraries.scss index 483aa2bae8..63a0f83987 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.scss +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.scss @@ -9,32 +9,34 @@ .libraries { margin-top: $s-8; width: 100%; +} - .selected-colors { - display: grid; - grid-template-columns: repeat(8, 1fr); - gap: $s-4; - justify-content: space-between; - overflow: auto; - margin-top: $s-8; - .add-color-btn, - .palette-btn { - @extend .button-secondary; - height: $s-24; - width: $s-24; - border-radius: $br-circle; - padding: 0; - svg { - @extend .button-icon; - } - } - } - .selected-colors::after { - content: ""; - flex: auto; - } +.selected-colors { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: $s-4; + justify-content: space-between; + overflow: auto; + margin-top: $s-8; +} - .select-wrapper { - overflow: initial; +.add-color-btn, +.palette-btn { + @extend .button-secondary; + height: $s-24; + width: $s-24; + border-radius: $br-circle; + padding: 0; + svg { + @extend .button-icon; } } + +.selected-colors::after { + content: ""; + flex: auto; +} + +.select-wrapper { + overflow: initial; +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs index 4063c40158..8b5ee82a30 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs @@ -9,16 +9,13 @@ (:require [app.common.colors :as cc] [app.common.math :as mth] - [app.main.ui.components.color-bullet :refer [color-bullet]] [app.main.ui.components.color-bullet-new :as cb] - [app.main.ui.context :as ctx] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.dom :as dom] [rumext.v2 :as mf])) (mf/defc value-saturation-selector [{:keys [saturation value on-change on-start-drag on-finish-drag]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - dragging? (mf/use-state false) + (let [dragging? (mf/use-state false) calculate-pos (fn [ev] (let [{:keys [left right top bottom]} (-> ev dom/get-target dom/get-bounding-rect) @@ -42,32 +39,20 @@ (dom/release-pointer event) (reset! dragging? false) (on-finish-drag)))] - (if new-css-system - [:div {:class (stl/css :value-saturation-selector) - :on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))} - [:div {:class (stl/css :handler) - :style {:pointer-events "none" - :left (str (* 100 saturation) "%") - :top (str (* 100 (- 1 (/ value 255))) "%")}}]] - - [:div.value-saturation-selector - {:on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))} - [:div.handler {:style {:pointer-events "none" - :left (str (* 100 saturation) "%") - :top (str (* 100 (- 1 (/ value 255))) "%")}}]]))) + [:div {:class (stl/css :value-saturation-selector) + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))} + [:div {:class (stl/css :handler) + :style {:pointer-events "none" + :left (str (* 100 saturation) "%") + :top (str (* 100 (- 1 (/ value 255))) "%")}}]])) (mf/defc ramp-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - {hex :hex + (let [{hex :hex hue :h saturation :s value :v alpha :alpha} color on-change-value-saturation @@ -90,60 +75,32 @@ on-change-opacity (fn [new-opacity] (on-change {:alpha new-opacity}))] - (if new-css-system - [:* - [:& value-saturation-selector - {:hue hue - :saturation saturation - :value value - :on-change on-change-value-saturation - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] + [:* + [:& value-saturation-selector + {:hue hue + :saturation saturation + :value value + :on-change on-change-value-saturation + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] - [:div {:class (stl/css new-css-system :shade-selector) - :style #js {"--bullet-size" "52px"}} - [:& cb/color-bullet {:color {:color hex - :opacity alpha} - :area true}] - [:div {:class (stl/css :sliders-wrapper)} - [:& slider-selector {:type :hue - :max-value 360 - :value hue - :on-change on-change-hue + [:div {:class (stl/css :shade-selector) + :style #js {"--bullet-size" "52px"}} + [:& cb/color-bullet {:color {:color hex + :opacity alpha} + :area true}] + [:div {:class (stl/css :sliders-wrapper)} + [:& slider-selector {:type :hue + :max-value 360 + :value hue + :on-change on-change-hue + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + + (when (not disable-opacity) + [:& slider-selector {:type :opacity + :max-value 1 + :value alpha + :on-change on-change-opacity :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - (when (not disable-opacity) - [:& slider-selector {:type :opacity - :max-value 1 - :value alpha - :on-change on-change-opacity - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])]]] - - [:* - [:& value-saturation-selector - {:hue hue - :saturation saturation - :value value - :on-change on-change-value-saturation - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - [:div.shade-selector - [:& color-bullet {:color {:color hex - :opacity alpha}}] - [:& slider-selector {:class "hue" - :max-value 360 - :value hue - :on-change on-change-hue - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - (when (not disable-opacity) - [:& slider-selector {:class "opacity" - :max-value 1 - :value alpha - :on-change on-change-opacity - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])]]))) + :on-finish-drag on-finish-drag}])]]])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.scss b/frontend/src/app/main/ui/workspace/colorpicker/ramp.scss index 450dcd9e57..512739d8fd 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.scss +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.scss @@ -15,13 +15,6 @@ margin-bottom: $s-12; cursor: pointer; - .handler { - @extend .colorpicker-handler; - height: $s-16; - width: $s-16; - border: $s-2 solid var(--colorpicker-handlers-color); - } - &::before { content: ""; position: absolute; @@ -38,12 +31,21 @@ background: linear-gradient(to top, #000, rgba(0, 0, 0, 0)); } } + +.handler { + @extend .colorpicker-handler; + height: $s-16; + width: $s-16; + border: $s-2 solid var(--colorpicker-handlers-color); +} + .shade-selector { display: flex; gap: $s-4; height: $s-52; cursor: pointer; } + .sliders-wrapper { @include flexColumn; } diff --git a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs index ddf475744d..1fa07db8a4 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs @@ -9,15 +9,13 @@ (:require [app.common.data.macros :as dm] [app.common.math :as mth] - [app.main.ui.context :as ctx] [app.util.dom :as dom] [app.util.object :as obj] [rumext.v2 :as mf])) (mf/defc slider-selector [{:keys [value class min-value max-value vertical? reverse? on-change on-start-drag on-finish-drag type]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - min-value (or min-value 0) + (let [min-value (or min-value 0) max-value (or max-value 1) dragging? (mf/use-state false) @@ -53,49 +51,27 @@ value (+ min-value (* unit-value (- max-value min-value)))] (on-change value))))] - (if new-css-system - [:div {:class (stl/css-case :opacity-wrapper (= type :opacity))} - [:div {:class (dm/str class (stl/css-case :vertical vertical? - :slider-selector true - :hue (= type :hue) - :opacity (= type :opacity) - :value (= type :value))) - :on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))} - (let [value-percent (* (/ (- value min-value) - (- max-value min-value)) 100) + [:div {:class (stl/css-case :opacity-wrapper (= type :opacity))} + [:div {:class (dm/str class (stl/css-case :vertical vertical? + :slider-selector true + :hue (= type :hue) + :opacity (= type :opacity) + :value (= type :value))) + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))} + (let [value-percent (* (/ (- value min-value) + (- max-value min-value)) 100) - value-percent (if reverse? - (mth/abs (- value-percent 100)) - value-percent) - value-percent-str (str value-percent "%") + value-percent (if reverse? + (mth/abs (- value-percent 100)) + value-percent) + value-percent-str (str value-percent "%") - style-common #js {:pointerEvents "none"} - style-horizontal (obj/merge! #js {:left value-percent-str} style-common) - style-vertical (obj/merge! #js {:bottom value-percent-str} style-common)] - [:div {:class (stl/css :handler) - :style (if vertical? style-vertical style-horizontal)}])]] - - [:div.slider-selector - {:class (str (if vertical? "vertical " "") class) - :on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))} - - (let [value-percent (* (/ (- value min-value) - (- max-value min-value)) 100) - - value-percent (if reverse? - (mth/abs (- value-percent 100)) - value-percent) - value-percent-str (str value-percent "%") - - style-common #js {:pointerEvents "none"} - style-horizontal (obj/merge! #js {:left value-percent-str} style-common) - style-vertical (obj/merge! #js {:bottom value-percent-str} style-common)] - [:div.handler {:style (if vertical? style-vertical style-horizontal)}])]))) + style-common #js {:pointerEvents "none"} + style-horizontal (obj/merge! #js {:left value-percent-str} style-common) + style-vertical (obj/merge! #js {:bottom value-percent-str} style-common)] + [:div {:class (stl/css :handler) + :style (if vertical? style-vertical style-horizontal)}])]])) From 7da949610d080345391e5541658ff942e69d34a7 Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 2 Jan 2024 17:57:20 +0100 Subject: [PATCH 11/35] :recycle: Remove new-css-system from interaction tab --- frontend/resources/styles/main-default.scss | 1 - .../main/partials/sidebar-interactions.scss | 215 -------------- .../sidebar/options/menus/interactions.scss | 280 +++++++++--------- 3 files changed, 147 insertions(+), 349 deletions(-) delete mode 100644 frontend/resources/styles/main/partials/sidebar-interactions.scss diff --git a/frontend/resources/styles/main-default.scss b/frontend/resources/styles/main-default.scss index 8243d1bb70..32288c6278 100644 --- a/frontend/resources/styles/main-default.scss +++ b/frontend/resources/styles/main-default.scss @@ -71,7 +71,6 @@ @import "main/partials/project-bar"; @import "main/partials/sidebar"; @import "main/partials/sidebar-document-history"; -@import "main/partials/sidebar-interactions"; @import "main/partials/tab-container"; @import "main/partials/tool-bar"; @import "main/partials/user-settings"; diff --git a/frontend/resources/styles/main/partials/sidebar-interactions.scss b/frontend/resources/styles/main/partials/sidebar-interactions.scss deleted file mode 100644 index 77c39c9a95..0000000000 --- a/frontend/resources/styles/main/partials/sidebar-interactions.scss +++ /dev/null @@ -1,215 +0,0 @@ -// 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 - -.interactions-help { - font-size: $fs12; - padding: 7px $size-4; - margin: 0 -7px; - text-align: center; - - &.separator { - padding-bottom: $size-4; - border-bottom: 1px solid $color-black; - } -} - -.interactions-help-icon { - height: 32px; - width: 32px; - margin: $size-4 auto; - - svg { - fill: $color-gray-40; - height: 32px; - width: 32px; - } -} - -.interactions-summary { - cursor: pointer; - flex-basis: 0; - flex-grow: 1; - - .trigger-name { - font-size: $fs12; - color: $color-white; - } - - .action-summary { - font-size: $fs12; - color: $color-gray-20; - } -} - -.interactions-element { - display: flex; - align-items: center; - margin: 0 -7px; - padding: 0 7px; - - .element-label { - color: $color-gray-20; - font-size: $fs12; - width: 64px; - } - - &.separator { - border-top: 1px solid $color-black; - margin-top: $size-1; - } -} - -.interactions-pos-buttons { - margin-top: $size-2; - padding-top: $size-2; - padding-bottom: $size-2; - justify-content: space-between; - - .element-set-actions-button { - min-width: 18px; - min-height: 18px; - } - - svg { - height: 18px; - width: 18px; - } -} - -.interactions-way-buttons { - display: grid; - grid-template-columns: 1fr 1fr; - - & .input-radio { - margin-bottom: 0; - - & label { - color: $color-gray-20; - - &:before { - background-color: unset; - } - } - - & input[type="radio"]:checked { - & + label { - &:before { - background-color: $color-primary; - box-shadow: inset 0 0 0 5px $color-gray-50; - } - } - } - } -} - -.interactions-direction-buttons { - margin-top: $size-2; - padding-top: $size-2; - padding-bottom: $size-2; - justify-content: space-around; - - .element-set-actions-button { - min-width: 40px; - min-height: 13px; - } - - svg { - height: 13px; - width: 13px; - } -} - -.interactions-easing-icon { - display: flex; - justify-content: center; - align-items: center; - min-width: 30px; - min-height: 30px; - - & svg { - width: 12px; - height: 12px; - stroke: $color-gray-20; - } -} - -.flow-element { - display: flex; - align-items: center; - padding: $size-1; - - .element-label { - font-size: $fs11; - } - - .flow-name { - cursor: pointer; - } - - & input.element-name { - background: transparent; - border-color: $color-primary; - color: $color-white; - font-size: $fs11; - } -} - -.flow-button { - cursor: pointer; - display: flex; - justify-content: center; - align-items: center; - margin-right: $size-2; - - & svg { - height: 12px; - width: 12px; - fill: $color-gray-20; - } - - &:hover svg { - fill: $color-primary; - } -} - -.flow-badge { - cursor: pointer; - display: flex; - - & .content { - align-items: center; - background-color: $color-gray-50; - border-radius: $br4; - display: flex; - height: 24px; - - & svg { - height: 12px; - margin: 0 $size-2; - width: 12px; - fill: $color-gray-20; - } - - & span { - color: $color-gray-20; - font-size: $fs12; - margin-right: $size-4; - } - } - - &.selected .content, - &:hover .content { - background-color: $color-primary; - - & svg { - fill: $color-gray-60; - } - - & span { - color: $color-gray-60; - } - } -} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss index 87eb4017a9..9ab6a9d811 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss @@ -10,69 +10,76 @@ display: flex; flex-direction: column; gap: $s-8; - .interaction-options { - @include flexColumn; - .element-title { - .add-interaction-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - } - } +} - .help-content { - padding: $s-20; - .help-group { - margin-bottom: $s-40; - .interactions-help-icon { - @include flexCenter; - width: $s-48; - height: $s-48; - border-radius: $br-circle; - background-color: var(--pill-background-color); - margin: 0 auto $s-12 auto; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - height: $s-32; - width: $s-32; - } - } - .interactions-help { - @include titleTipography; - text-align: center; - } - } - } +.interaction-options { + @include flexColumn; +} + +.add-interaction-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); } - .element-set { - @include flexColumn; - .add-flow-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } +} + +.help-content { + padding: $s-20; +} + +.help-group { + margin-bottom: $s-40; +} + +.interactions-help-icon { + @include flexCenter; + width: $s-48; + height: $s-48; + border-radius: $br-circle; + background-color: var(--pill-background-color); + margin: 0 auto $s-12 auto; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + height: $s-32; + width: $s-32; + } +} + +.interactions-help { + @include titleTipography; + text-align: center; + color: var(--title-foreground-color); +} + +.element-set { + @include flexColumn; +} + +.add-flow-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; } } .interactions-info { flex-grow: 1; display: grid; +} - .trigger-name { - color: var(--color-foreground-primary); - } - .action-summary { - color: var(--color-foreground-secondary); - @include textEllipsis; - } +.trigger-name { + color: var(--color-foreground-primary); +} + +.action-summary { + color: var(--color-foreground-secondary); + @include textEllipsis; } .groups { @@ -96,6 +103,7 @@ width: $s-92; margin: auto 0; grid-area: name; + color: var(--title-foreground-color); } .select-wrapper { display: flex; @@ -231,91 +239,97 @@ .flow-element { @include flexRow; - .flow-info { - display: flex; - align-items: center; - gap: $s-2; - border-radius: $s-8; - background-color: var(--input-details-color); - height: $s-32; - width: 100%; - flex-grow: 1; - .flow-name-wrapper { - @include titleTipography; - @include focusInput; - display: flex; - align-items: center; - gap: $s-4; - flex-grow: 1; - height: $s-32; - width: 100%; - border-radius: $br-8; - padding: 0; - margin-right: 0; - background-color: var(--input-background-color); - border: $s-1 solid var(--input-background-color); - color: var(--input-foreground-color); - .start-flow-btn { - @include buttonStyle; - height: $s-32; - width: $s-28; - padding: 0 $s-2 0 $s-8; - border-radius: $br-8 0 0 $br-8; - background-color: transparent; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - &:hover { - stroke: var(--input-foreground-color-active); - } - } - } - .flow-input { - @extend .input-base; - background-color: transparent; - height: $s-28; - } - .flow-input-wrapper { - @include titleTipography; - display: flex; - align-items: center; - height: $s-28; - padding: 0; - width: 100%; - margin: 0; - flex-grow: 1; - background-color: transparent; - color: var(--input-foreground-color); - border-radius: $br-8; - } - &:hover { - background-color: var(--input-background-color-hover); - border: $s-1 solid var(--input-background-color-hover); - &:active { - background-color: var(--input-background-color-active); - .flow-input-wrapper { - background-color: var(--input-background-color-active); - } - } - } - &:focus, - &:focus-within { - background-color: var(--input-background-color-active); - } +} - &.editing { - background-color: var(--input-background-color-active); - } - } - } +.flow-info { + display: flex; + align-items: center; + gap: $s-2; + border-radius: $s-8; + background-color: var(--input-details-color); + height: $s-32; + width: 100%; + flex-grow: 1; +} - .remove-flow-btn { - @extend .button-tertiary; +.flow-name-wrapper { + @include titleTipography; + @include focusInput; + display: flex; + align-items: center; + gap: $s-4; + flex-grow: 1; + height: $s-32; + width: 100%; + border-radius: $br-8; + padding: 0; + margin-right: 0; + background-color: var(--input-background-color); + border: $s-1 solid var(--input-background-color); + color: var(--input-foreground-color); + .start-flow-btn { + @include buttonStyle; height: $s-32; width: $s-28; - min-width: $s-28; + padding: 0 $s-2 0 $s-8; + border-radius: $br-8 0 0 $br-8; + background-color: transparent; svg { @extend .button-icon; + stroke: var(--icon-foreground); + &:hover { + stroke: var(--input-foreground-color-active); + } } } + + .flow-input { + @extend .input-base; + background-color: transparent; + height: $s-28; + } + + .flow-input-wrapper { + @include titleTipography; + display: flex; + align-items: center; + height: $s-28; + padding: 0; + width: 100%; + margin: 0; + flex-grow: 1; + background-color: transparent; + color: var(--input-foreground-color); + border-radius: $br-8; + } + + &:hover { + background-color: var(--input-background-color-hover); + border: $s-1 solid var(--input-background-color-hover); + &:active { + background-color: var(--input-background-color-active); + .flow-input-wrapper { + background-color: var(--input-background-color-active); + } + } + } + + &:focus, + &:focus-within { + background-color: var(--input-background-color-active); + } + + &.editing { + background-color: var(--input-background-color-active); + } +} + +.remove-flow-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + min-width: $s-28; + svg { + @extend .button-icon; + } } From e6fb96c4c2b564b474fed9adf278450ee1d400c5 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 29 Dec 2023 15:21:01 +0100 Subject: [PATCH 12/35] :paperclip: Update .gitignore file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8883932e85..0e271d1257 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ /*.jpg /*.md /*.png +/*.svg /*.sql /*.txt /*.yml From addb392ecc68248bcb6e029663d10c7a7afffde6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 29 Dec 2023 15:21:14 +0100 Subject: [PATCH 13/35] :sparkles: Add safety mechanism for direct object deletion The main objective is prevent deletion of objects that can leave unreachable orphan objects which we are unable to correctly track. Additionally, this commit includes: 1. Properly implement safe cascade deletion of all participating tables on soft deletion in the objects-gc task; 2. Make the file thumbnail related tables also participate in the touch/refcount mechanism applyign to the same safety checks; 3. Add helper for db query lazy iteration using PostgreSQL support for server side cursors; 4. Fix efficiency issues on gc related task using server side cursors instead of custom chunked iteration for processing data. The problem resided when a large chunk of rows that has identical value on the deleted_at column and the chunk size is small (the default); when the custom chunked iteration only reads a first N items and skip the rest of the set to the next run. This has caused many objects to remain pending to be eliminated, taking up space for longer than expected. The server side cursor based iteration does not has this problem and iterates correctly over all objects. 5. Fix refcount issues on font variant deletion RPC methods --- backend/src/app/db.clj | 19 + backend/src/app/loggers/audit.clj | 48 +- backend/src/app/main.clj | 17 +- backend/src/app/migrations.clj | 35 +- ...d-deletion-protection-trigger-function.sql | 8 + .../sql/0108-mod-file-thumbnail-table.sql | 25 + ...mod-file-tagged-object-thumbnail-table.sql | 26 + .../sql/0110-mod-file-media-object-table.sql | 27 + .../sql/0111-mod-file-data-fragment-table.sql | 9 + .../migrations/sql/0112-mod-profile-table.sql | 15 + .../sql/0113-mod-team-font-variant-table.sql | 20 + .../migrations/sql/0114-mod-team-table.sql | 10 + .../migrations/sql/0115-mod-project-table.sql | 3 + .../migrations/sql/0116-mod-file-table.sql | 3 + .../0117-mod-file-object-thumbnail-table.sql | 12 + backend/src/app/rpc/commands/auth.clj | 4 +- backend/src/app/rpc/commands/comments.clj | 26 +- backend/src/app/rpc/commands/files.clj | 2 +- .../src/app/rpc/commands/files_thumbnails.clj | 179 ++++--- backend/src/app/rpc/commands/fonts.clj | 214 ++++---- backend/src/app/rpc/commands/media.clj | 7 + backend/src/app/rpc/retry.clj | 77 +-- backend/src/app/storage.clj | 224 --------- backend/src/app/storage/gc_deleted.clj | 128 +++++ backend/src/app/storage/gc_touched.clj | 208 ++++++++ backend/src/app/storage/impl.clj | 9 +- backend/src/app/tasks/file_gc.clj | 317 ++++++------ backend/src/app/tasks/objects_gc.clj | 465 +++++++++++------- backend/src/app/tasks/orphan_teams_gc.clj | 60 +++ backend/test/backend_tests/helpers.clj | 15 +- backend/test/backend_tests/rpc_file_test.clj | 152 ++++-- .../rpc_file_thumbnails_test.clj | 55 ++- backend/test/backend_tests/rpc_font_test.clj | 189 +++++++ .../test/backend_tests/rpc_profile_test.clj | 76 +-- .../test/backend_tests/rpc_project_test.clj | 10 +- backend/test/backend_tests/rpc_team_test.clj | 186 ++++--- backend/test/backend_tests/storage_test.clj | 64 +-- 37 files changed, 1918 insertions(+), 1026 deletions(-) create mode 100644 backend/src/app/migrations/sql/0107-add-deletion-protection-trigger-function.sql create mode 100644 backend/src/app/migrations/sql/0108-mod-file-thumbnail-table.sql create mode 100644 backend/src/app/migrations/sql/0109-mod-file-tagged-object-thumbnail-table.sql create mode 100644 backend/src/app/migrations/sql/0110-mod-file-media-object-table.sql create mode 100644 backend/src/app/migrations/sql/0111-mod-file-data-fragment-table.sql create mode 100644 backend/src/app/migrations/sql/0112-mod-profile-table.sql create mode 100644 backend/src/app/migrations/sql/0113-mod-team-font-variant-table.sql create mode 100644 backend/src/app/migrations/sql/0114-mod-team-table.sql create mode 100644 backend/src/app/migrations/sql/0115-mod-project-table.sql create mode 100644 backend/src/app/migrations/sql/0116-mod-file-table.sql create mode 100644 backend/src/app/migrations/sql/0117-mod-file-object-thumbnail-table.sql create mode 100644 backend/src/app/storage/gc_deleted.clj create mode 100644 backend/src/app/storage/gc_touched.clj create mode 100644 backend/src/app/tasks/orphan_teams_gc.clj diff --git a/backend/src/app/db.clj b/backend/src/app/db.clj index 8d7fbef4c9..3577370222 100644 --- a/backend/src/app/db.clj +++ b/backend/src/app/db.clj @@ -341,6 +341,25 @@ (-> (get-connectable ds) (jdbc/plan sql sql/default-opts))) +(defn cursor + "Return a lazy seq of rows using server side cursors" + [conn query & {:keys [chunk-size] :or {chunk-size 25}}] + (let [cname (str (gensym "cursor_")) + fquery [(str "FETCH " chunk-size " FROM " cname)]] + + ;; declare cursor + (exec-one! conn + (if (vector? query) + (into [(str "DECLARE " cname " CURSOR FOR " (nth query 0))] + (rest query)) + [(str "DECLARE " cname " CURSOR FOR " query)])) + + ;; return a lazy seq + ((fn fetch-more [] + (lazy-seq + (when-let [chunk (seq (exec! conn fquery))] + (concat chunk (fetch-more)))))))) + (defn get-by-id [ds table id & {:as opts}] (get ds table {:id id} opts)) diff --git a/backend/src/app/loggers/audit.clj b/backend/src/app/loggers/audit.clj index 4171f52ab3..3fbd09bddf 100644 --- a/backend/src/app/loggers/audit.clj +++ b/backend/src/app/loggers/audit.clj @@ -133,7 +133,7 @@ [_ {:keys [::db/pool] :as cfg}] (cond (db/read-only? pool) - (l/warn :hint "audit: disabled (db is read-only)") + (l/warn :hint "audit disabled (db is read-only)") :else cfg)) @@ -187,8 +187,7 @@ false)})) (defn- handle-event! - [conn-or-pool event] - (us/verify! ::event event) + [cfg event] (let [params {:id (uuid/next) :name (::name event) :type (::type event) @@ -201,19 +200,22 @@ ;; NOTE: this operation may cause primary key conflicts on inserts ;; because of the timestamp precission (two concurrent requests), in ;; this case we just retry the operation. - (rtry/with-retry {::rtry/when rtry/conflict-exception? - ::rtry/max-retries 6 - ::rtry/label "persist-audit-log" - ::db/conn (dm/check db/connection? conn-or-pool)} - (let [now (dt/now)] - (db/insert! conn-or-pool :audit-log - (-> params - (update :props db/tjson) - (update :context db/tjson) - (update :ip-addr db/inet) - (assoc :created-at now) - (assoc :tracked-at now) - (assoc :source "backend")))))) + (let [cfg (-> cfg + (assoc ::rtry/when rtry/conflict-exception?) + (assoc ::rtry/max-retries 6) + (assoc ::rtry/label "persist-audit-log")) + params (-> params + (update :props db/tjson) + (update :context db/tjson) + (update :ip-addr db/inet) + (assoc :source "backend"))] + + (rtry/invoke cfg (fn [cfg] + (let [tnow (dt/now) + params (-> params + (assoc :created-at tnow) + (assoc :tracked-at tnow))] + (db/insert! cfg :audit-log params)))))) (when (and (contains? cf/flags :webhooks) (::webhooks/event? event)) @@ -226,7 +228,7 @@ :else label) dedupe? (boolean (and batch-key batch-timeout))] - (wrk/submit! ::wrk/conn conn-or-pool + (wrk/submit! ::wrk/conn (::db/conn cfg) ::wrk/task :process-webhook-event ::wrk/queue :webhooks ::wrk/max-retries 0 @@ -243,12 +245,12 @@ (defn submit! "Submit audit event to the collector." [cfg params] - (let [conn (or (::db/conn cfg) (::db/pool cfg))] - (us/assert! ::db/pool-or-conn conn) - (try - (handle-event! conn (d/without-nils params)) - (catch Throwable cause - (l/error :hint "audit: unexpected error processing event" :cause cause))))) + (try + (let [event (d/without-nils params)] + (us/verify! ::event event) + (db/tx-run! cfg handle-event! event)) + (catch Throwable cause + (l/error :hint "unexpected error processing event" :cause cause)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; TASK: ARCHIVE diff --git a/backend/src/app/main.clj b/backend/src/app/main.clj index 953f51d8be..dde88473b7 100644 --- a/backend/src/app/main.clj +++ b/backend/src/app/main.clj @@ -34,6 +34,8 @@ [app.srepl :as-alias srepl] [app.storage :as-alias sto] [app.storage.fs :as-alias sto.fs] + [app.storage.gc-deleted :as-alias sto.gc-deleted] + [app.storage.gc-touched :as-alias sto.gc-touched] [app.storage.s3 :as-alias sto.s3] [app.util.time :as dt] [app.worker :as-alias wrk] @@ -202,11 +204,11 @@ :app.storage.tmp/cleaner {::wrk/executor (ig/ref ::wrk/executor)} - ::sto/gc-deleted-task + ::sto.gc-deleted/handler {::db/pool (ig/ref ::db/pool) ::sto/storage (ig/ref ::sto/storage)} - ::sto/gc-touched-task + ::sto.gc-touched/handler {::db/pool (ig/ref ::db/pool)} ::http.client/client @@ -337,12 +339,13 @@ ::wrk/tasks {:sendmail (ig/ref ::email/handler) :objects-gc (ig/ref :app.tasks.objects-gc/handler) + :orphan-teams-gc (ig/ref :app.tasks.orphan-teams-gc/handler) :file-gc (ig/ref :app.tasks.file-gc/handler) :file-xlog-gc (ig/ref :app.tasks.file-xlog-gc/handler) - :storage-gc-deleted (ig/ref ::sto/gc-deleted-task) - :storage-gc-touched (ig/ref ::sto/gc-touched-task) :tasks-gc (ig/ref :app.tasks.tasks-gc/handler) :telemetry (ig/ref :app.tasks.telemetry/handler) + :storage-gc-deleted (ig/ref ::sto.gc-deleted/handler) + :storage-gc-touched (ig/ref ::sto.gc-touched/handler) :session-gc (ig/ref ::session.tasks/gc) :audit-log-archive (ig/ref ::audit.tasks/archive) :audit-log-gc (ig/ref ::audit.tasks/gc) @@ -373,6 +376,9 @@ {::db/pool (ig/ref ::db/pool) ::sto/storage (ig/ref ::sto/storage)} + :app.tasks.orphan-teams-gc/handler + {::db/pool (ig/ref ::db/pool)} + :app.tasks.file-gc/handler {::db/pool (ig/ref ::db/pool) ::sto/storage (ig/ref ::sto/storage)} @@ -458,6 +464,9 @@ {:cron #app/cron "0 0 0 * * ?" ;; daily :task :objects-gc} + {:cron #app/cron "0 0 0 * * ?" ;; daily + :task :orphan-teams-gc} + {:cron #app/cron "0 0 0 * * ?" ;; daily :task :storage-gc-deleted} diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj index d37c7fc32b..900ef75f53 100644 --- a/backend/src/app/migrations.clj +++ b/backend/src/app/migrations.clj @@ -337,7 +337,40 @@ :fn (mg/resource "app/migrations/sql/0106-mod-team-table.sql")} {:name "0107-mod-file-tagged-object-thumbnail-table" - :fn (mg/resource "app/migrations/sql/0107-mod-file-tagged-object-thumbnail-table.sql")}]) + :fn (mg/resource "app/migrations/sql/0107-mod-file-tagged-object-thumbnail-table.sql")} + + {:name "0107-add-deletion-protection-trigger-function" + :fn (mg/resource "app/migrations/sql/0107-add-deletion-protection-trigger-function.sql")} + + {:name "0108-mod-file-thumbnail-table" + :fn (mg/resource "app/migrations/sql/0108-mod-file-thumbnail-table.sql")} + + {:name "0109-mod-file-tagged-object-thumbnail-table" + :fn (mg/resource "app/migrations/sql/0109-mod-file-tagged-object-thumbnail-table.sql")} + + {:name "0110-mod-file-media-object-table" + :fn (mg/resource "app/migrations/sql/0110-mod-file-media-object-table.sql")} + + {:name "0111-mod-file-data-fragment-table" + :fn (mg/resource "app/migrations/sql/0111-mod-file-data-fragment-table.sql")} + + {:name "0112-mod-profile-table" + :fn (mg/resource "app/migrations/sql/0112-mod-profile-table.sql")} + + {:name "0113-mod-team-font-variant-table" + :fn (mg/resource "app/migrations/sql/0113-mod-team-font-variant-table.sql")} + + {:name "0114-mod-team-table" + :fn (mg/resource "app/migrations/sql/0114-mod-team-table.sql")} + + {:name "0115-mod-project-table" + :fn (mg/resource "app/migrations/sql/0115-mod-project-table.sql")} + + {:name "0116-mod-file-table" + :fn (mg/resource "app/migrations/sql/0116-mod-file-table.sql")} + + {:name "0117-mod-file-object-thumbnail-table" + :fn (mg/resource "app/migrations/sql/0117-mod-file-object-thumbnail-table.sql")}]) (defn apply-migrations! [pool name migrations] diff --git a/backend/src/app/migrations/sql/0107-add-deletion-protection-trigger-function.sql b/backend/src/app/migrations/sql/0107-add-deletion-protection-trigger-function.sql new file mode 100644 index 0000000000..1ccf9b8b79 --- /dev/null +++ b/backend/src/app/migrations/sql/0107-add-deletion-protection-trigger-function.sql @@ -0,0 +1,8 @@ +CREATE OR REPLACE FUNCTION raise_deletion_protection() + RETURNS TRIGGER AS $$ + BEGIN + RAISE EXCEPTION 'unable to proceed to delete row on "%"', TG_TABLE_NAME + USING HINT = 'disable deletion protection with "SET rules.deletion_protection TO off"'; + RETURN NULL; + END; +$$ LANGUAGE plpgsql; diff --git a/backend/src/app/migrations/sql/0108-mod-file-thumbnail-table.sql b/backend/src/app/migrations/sql/0108-mod-file-thumbnail-table.sql new file mode 100644 index 0000000000..b7d05bdc7f --- /dev/null +++ b/backend/src/app/migrations/sql/0108-mod-file-thumbnail-table.sql @@ -0,0 +1,25 @@ +--- Add missing index for deleted_at column, we include all related +--- columns because we expect the index to be small and expect use +--- index-only scans. +CREATE INDEX IF NOT EXISTS file_thumbnail__deleted_at__idx + ON file_thumbnail (deleted_at, file_id, revn, media_id) + WHERE deleted_at IS NOT NULL; + +--- Add missing for media_id column, used mainly for refs checking +CREATE INDEX IF NOT EXISTS file_thumbnail__media_id__idx ON file_thumbnail (media_id); + +--- Remove CASCADE from media_id and file_id foreign constraint +ALTER TABLE file_thumbnail + DROP CONSTRAINT file_thumbnail_file_id_fkey, + ADD FOREIGN KEY (file_id) REFERENCES file(id) DEFERRABLE; + +ALTER TABLE file_thumbnail + DROP CONSTRAINT file_thumbnail_media_id_fkey, + ADD FOREIGN KEY (media_id) REFERENCES storage_object(id) DEFERRABLE; + +--- Add deletion protection +CREATE OR REPLACE TRIGGER deletion_protection__tgr +BEFORE DELETE ON file_thumbnail FOR EACH STATEMENT + WHEN ((current_setting('rules.deletion_protection', true) IN ('on', '')) OR + (current_setting('rules.deletion_protection', true) IS NULL)) + EXECUTE PROCEDURE raise_deletion_protection(); diff --git a/backend/src/app/migrations/sql/0109-mod-file-tagged-object-thumbnail-table.sql b/backend/src/app/migrations/sql/0109-mod-file-tagged-object-thumbnail-table.sql new file mode 100644 index 0000000000..3184a6576f --- /dev/null +++ b/backend/src/app/migrations/sql/0109-mod-file-tagged-object-thumbnail-table.sql @@ -0,0 +1,26 @@ +ALTER TABLE file_tagged_object_thumbnail + ADD COLUMN updated_at timestamptz NULL, + ADD COLUMN deleted_at timestamptz NULL; + +--- Add index for deleted_at column, we include all related columns +--- because we expect the index to be small and expect use index-only +--- scans. +CREATE INDEX IF NOT EXISTS file_tagged_object_thumbnail__deleted_at__idx + ON file_tagged_object_thumbnail (deleted_at, file_id, object_id, media_id) + WHERE deleted_at IS NOT NULL; + +--- Remove CASCADE from media_id and file_id foreign constraint +ALTER TABLE file_tagged_object_thumbnail + DROP CONSTRAINT file_tagged_object_thumbnail_media_id_fkey, + ADD FOREIGN KEY (media_id) REFERENCES storage_object(id) DEFERRABLE; + +ALTER TABLE file_tagged_object_thumbnail + DROP CONSTRAINT file_tagged_object_thumbnail_file_id_fkey, + ADD FOREIGN KEY (file_id) REFERENCES file(id) DEFERRABLE; + +--- Add deletion protection +CREATE OR REPLACE TRIGGER deletion_protection__tgr +BEFORE DELETE ON file_tagged_object_thumbnail FOR EACH STATEMENT + WHEN ((current_setting('rules.deletion_protection', true) IN ('on', '')) OR + (current_setting('rules.deletion_protection', true) IS NULL)) + EXECUTE PROCEDURE raise_deletion_protection(); diff --git a/backend/src/app/migrations/sql/0110-mod-file-media-object-table.sql b/backend/src/app/migrations/sql/0110-mod-file-media-object-table.sql new file mode 100644 index 0000000000..49cbebc96c --- /dev/null +++ b/backend/src/app/migrations/sql/0110-mod-file-media-object-table.sql @@ -0,0 +1,27 @@ +--- Fix legacy naming +ALTER INDEX media_object_pkey RENAME TO file_media_object_pkey; +ALTER INDEX media_object__file_id__idx RENAME TO file_media_object__file_id__idx; + +--- Create index for the deleted_at column +CREATE INDEX IF NOT EXISTS file_media_object__deleted_at__idx + ON file_media_object (deleted_at, id, media_id) + WHERE deleted_at IS NOT NULL; + +--- Drop now unnecesary trigger because this will be handled by the +--- application code +DROP TRIGGER file_media_object__on_delete__tgr ON file_media_object; +DROP FUNCTION on_delete_file_media_object ( ) CASCADE; +DROP TRIGGER file_media_object__on_insert__tgr ON file_media_object; +DROP FUNCTION on_media_object_insert () CASCADE; + +--- Remove CASCADE from file FOREIGN KEY +ALTER TABLE file_media_object + DROP CONSTRAINT file_media_object_file_id_fkey, + ADD FOREIGN KEY (file_id) REFERENCES file(id) DEFERRABLE; + +--- Add deletion protection +CREATE OR REPLACE TRIGGER deletion_protection__tgr +BEFORE DELETE ON file_media_object FOR EACH STATEMENT + WHEN ((current_setting('rules.deletion_protection', true) IN ('on', '')) OR + (current_setting('rules.deletion_protection', true) IS NULL)) + EXECUTE PROCEDURE raise_deletion_protection(); diff --git a/backend/src/app/migrations/sql/0111-mod-file-data-fragment-table.sql b/backend/src/app/migrations/sql/0111-mod-file-data-fragment-table.sql new file mode 100644 index 0000000000..8397124c3f --- /dev/null +++ b/backend/src/app/migrations/sql/0111-mod-file-data-fragment-table.sql @@ -0,0 +1,9 @@ +ALTER TABLE file_data_fragment + ADD COLUMN deleted_at timestamptz NULL; + +--- Add index for deleted_at column, we include all related columns +--- because we expect the index to be small and expect use index-only +--- scans. +CREATE INDEX IF NOT EXISTS file_data_fragment__deleted_at__idx + ON file_data_fragment (deleted_at, file_id, id) + WHERE deleted_at IS NOT NULL; diff --git a/backend/src/app/migrations/sql/0112-mod-profile-table.sql b/backend/src/app/migrations/sql/0112-mod-profile-table.sql new file mode 100644 index 0000000000..2db8d75b0a --- /dev/null +++ b/backend/src/app/migrations/sql/0112-mod-profile-table.sql @@ -0,0 +1,15 @@ +ALTER TABLE profile + DROP CONSTRAINT profile_photo_id_fkey, + ADD FOREIGN KEY (photo_id) REFERENCES storage_object(id) DEFERRABLE, + DROP CONSTRAINT profile_default_project_id_fkey, + ADD FOREIGN KEY (default_project_id) REFERENCES project(id) DEFERRABLE, + DROP CONSTRAINT profile_default_team_id_fkey, + ADD FOREIGN KEY (default_team_id) REFERENCES team(id) DEFERRABLE; + +--- Add deletion protection +CREATE OR REPLACE TRIGGER deletion_protection__tgr +BEFORE DELETE ON profile FOR EACH STATEMENT + WHEN ((current_setting('rules.deletion_protection', true) IN ('on', '')) OR + (current_setting('rules.deletion_protection', true) IS NULL)) + EXECUTE PROCEDURE raise_deletion_protection(); + diff --git a/backend/src/app/migrations/sql/0113-mod-team-font-variant-table.sql b/backend/src/app/migrations/sql/0113-mod-team-font-variant-table.sql new file mode 100644 index 0000000000..b9caa08f6e --- /dev/null +++ b/backend/src/app/migrations/sql/0113-mod-team-font-variant-table.sql @@ -0,0 +1,20 @@ +--- Remove ON DELETE SET NULL from foreign constraint on +--- storage_object table +ALTER TABLE team_font_variant + DROP CONSTRAINT team_font_variant_otf_file_id_fkey, + ADD FOREIGN KEY (otf_file_id) REFERENCES storage_object(id) DEFERRABLE, + DROP CONSTRAINT team_font_variant_ttf_file_id_fkey, + ADD FOREIGN KEY (ttf_file_id) REFERENCES storage_object(id) DEFERRABLE, + DROP CONSTRAINT team_font_variant_woff1_file_id_fkey, + ADD FOREIGN KEY (woff1_file_id) REFERENCES storage_object(id) DEFERRABLE, + DROP CONSTRAINT team_font_variant_woff2_file_id_fkey, + ADD FOREIGN KEY (woff2_file_id) REFERENCES storage_object(id) DEFERRABLE, + DROP CONSTRAINT team_font_variant_team_id_fkey, + ADD FOREIGN KEY (team_id) REFERENCES team(id) DEFERRABLE; + +--- Add deletion protection +CREATE OR REPLACE TRIGGER deletion_protection__tgr +BEFORE DELETE ON team_font_variant FOR EACH STATEMENT + WHEN ((current_setting('rules.deletion_protection', true) IN ('on', '')) OR + (current_setting('rules.deletion_protection', true) IS NULL)) + EXECUTE PROCEDURE raise_deletion_protection(); diff --git a/backend/src/app/migrations/sql/0114-mod-team-table.sql b/backend/src/app/migrations/sql/0114-mod-team-table.sql new file mode 100644 index 0000000000..8c76756437 --- /dev/null +++ b/backend/src/app/migrations/sql/0114-mod-team-table.sql @@ -0,0 +1,10 @@ +--- Add deletion protection +CREATE OR REPLACE TRIGGER deletion_protection__tgr +BEFORE DELETE ON team FOR EACH STATEMENT + WHEN ((current_setting('rules.deletion_protection', true) IN ('on', '')) OR + (current_setting('rules.deletion_protection', true) IS NULL)) + EXECUTE PROCEDURE raise_deletion_protection(); + +ALTER TABLE team + DROP CONSTRAINT team_photo_id_fkey, + ADD FOREIGN KEY (photo_id) REFERENCES storage_object(id) DEFERRABLE; diff --git a/backend/src/app/migrations/sql/0115-mod-project-table.sql b/backend/src/app/migrations/sql/0115-mod-project-table.sql new file mode 100644 index 0000000000..f37470dce8 --- /dev/null +++ b/backend/src/app/migrations/sql/0115-mod-project-table.sql @@ -0,0 +1,3 @@ +ALTER TABLE project + DROP CONSTRAINT project_team_id_fkey, + ADD FOREIGN KEY (team_id) REFERENCES team(id) DEFERRABLE; diff --git a/backend/src/app/migrations/sql/0116-mod-file-table.sql b/backend/src/app/migrations/sql/0116-mod-file-table.sql new file mode 100644 index 0000000000..1d3bce11a2 --- /dev/null +++ b/backend/src/app/migrations/sql/0116-mod-file-table.sql @@ -0,0 +1,3 @@ +ALTER TABLE file + DROP CONSTRAINT file_project_id_fkey, + ADD FOREIGN KEY (project_id) REFERENCES project(id) DEFERRABLE; diff --git a/backend/src/app/migrations/sql/0117-mod-file-object-thumbnail-table.sql b/backend/src/app/migrations/sql/0117-mod-file-object-thumbnail-table.sql new file mode 100644 index 0000000000..e3f6cb6d4b --- /dev/null +++ b/backend/src/app/migrations/sql/0117-mod-file-object-thumbnail-table.sql @@ -0,0 +1,12 @@ +ALTER TABLE file_object_thumbnail + DROP CONSTRAINT file_object_thumbnail_file_id_fkey, + ADD FOREIGN KEY (file_id) REFERENCES file(id) DEFERRABLE, + DROP CONSTRAINT file_object_thumbnail_media_id_fkey, + ADD FOREIGN KEY (media_id) REFERENCES storage_object(id) DEFERRABLE; + +--- Mark all related storage_object row as touched +-- UPDATE storage_object SET touched_at = now() +-- WHERE id IN (SELECT DISTINCT media_id +-- FROM file_object_thumbnail +-- WHERE media_id IS NOT NULL) +-- AND touched_at IS NULL; diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index 13d05bf0f3..d3be9ac1b8 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -54,7 +54,9 @@ :hint "the current account does not have password") (let [result (profile/verify-password cfg password (:password profile))] (when (:update result) - (l/trace :hint "updating profile password" :id (:id profile) :email (:email profile)) + (l/trc :hint "updating profile password" + :id (str (:id profile)) + :email (:email profile)) (profile/update-profile-password! conn (assoc profile :password password))) (:valid result)))) diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj index 5e87884f6d..99f6094b4b 100644 --- a/backend/src/app/rpc/commands/comments.clj +++ b/backend/src/app/rpc/commands/comments.clj @@ -309,23 +309,21 @@ ::quotes/project-id project-id ::quotes/file-id file-id})) - (rtry/with-retry {::rtry/when rtry/conflict-exception? - ::rtry/max-retries 3 - ::rtry/label "create-comment-thread" - ::db/conn conn} - (create-comment-thread conn - {:created-at request-at - :profile-id profile-id - :file-id file-id - :page-id page-id - :page-name page-name - :position position - :content content - :frame-id frame-id})))))) + (-> cfg + (assoc ::rtry/when rtry/conflict-exception?) + (assoc ::rtry/label "create-comment-thread") + (rtry/invoke create-comment-thread {:created-at request-at + :profile-id profile-id + :file-id file-id + :page-id page-id + :page-name page-name + :position position + :content content + :frame-id frame-id})))))) (defn- create-comment-thread - [conn {:keys [profile-id file-id page-id page-name created-at position content frame-id]}] + [{:keys [::db/conn]} {:keys [profile-id file-id page-id page-name created-at position content frame-id]}] (let [;; NOTE: we take the next seq number from a separate query because the whole ;; operation can be retried on conflict, and in this case the new seq shold be ;; retrieved from the database. diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 096e961957..2bb6cd9b66 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -516,7 +516,7 @@ ft.media_id from file as f inner join project as p on (p.id = f.project_id) - left join file_thumbnail as ft on (ft.file_id = f.id and ft.revn = f.revn) + left join file_thumbnail as ft on (ft.file_id = f.id and ft.revn = f.revn and ft.deleted_at is null) where f.is_shared = true and f.deleted_at is null and p.deleted_at is null diff --git a/backend/src/app/rpc/commands/files_thumbnails.clj b/backend/src/app/rpc/commands/files_thumbnails.clj index 19f36072f4..c34fedaff1 100644 --- a/backend/src/app/rpc/commands/files_thumbnails.clj +++ b/backend/src/app/rpc/commands/files_thumbnails.clj @@ -27,6 +27,7 @@ [app.rpc.commands.teams :as teams] [app.rpc.cond :as-alias cond] [app.rpc.doc :as-alias doc] + [app.rpc.retry :as rtry] [app.storage :as sto] [app.util.pointer-map :as pmap] [app.util.services :as sv] @@ -46,7 +47,7 @@ (let [sql (str/concat "select object_id, media_id, tag " " from file_tagged_object_thumbnail" - " where file_id=? and tag=?") + " where file_id=? and tag=? and deleted_at is null") res (db/exec! conn [sql file-id tag])] (->> res (d/index-by :object-id (fn [row] @@ -58,7 +59,7 @@ (let [sql (str/concat "select object_id, media_id, tag " " from file_tagged_object_thumbnail" - " where file_id=?") + " where file_id=? and deleted_at is null") res (db/exec! conn [sql file-id])] (->> res (d/index-by :object-id (fn [row] @@ -69,7 +70,7 @@ (let [sql (str/concat "select object_id, media_id, tag " " from file_tagged_object_thumbnail" - " where file_id=? and object_id = ANY(?)") + " where file_id=? and object_id = ANY(?) and deleted_at is null") ids (db/create-array conn "text" (seq object-ids)) res (db/exec! conn [sql file-id ids])] @@ -226,34 +227,54 @@ ;; MUTATION COMMANDS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; --- MUTATION COMMAND: create-file-object-thumbnail - -(def ^:private sql:create-object-thumbnail - "insert into file_tagged_object_thumbnail(file_id, object_id, media_id, tag) - values (?, ?, ?, ?) - on conflict(file_id, tag, object_id) do - update set media_id = ? - returning *;") +;; MUTATION COMMAND: create-file-object-thumbnail (defn- create-file-object-thumbnail! [{:keys [::db/conn ::sto/storage]} file-id object-id media tag] - (let [path (:path media) + (let [thumb (db/get* conn :file-tagged-object-thumbnail + {:file-id file-id + :object-id object-id + :tag tag} + {::db/remove-deleted? false + ::db/for-update? true}) + + path (:path media) mtype (:mtype media) hash (sto/calculate-hash path) data (-> (sto/content path) (sto/wrap-with-hash hash)) + tnow (dt/now) + media (sto/put-object! storage {::sto/content data ::sto/deduplicate? true - ::sto/touched-at (dt/now) + ::sto/touched-at tnow :content-type mtype :bucket "file-object-thumbnail"})] - (db/exec-one! conn [sql:create-object-thumbnail file-id object-id - (:id media) tag (:id media)]))) + (if (some? thumb) + (do + ;; We mark the old media id as touched if it does not matches + (when (not= (:id media) (:media-id thumb)) + (sto/touch-object! storage (:media-id thumb))) + (db/update! conn :file-tagged-object-thumbnail + {:media-id (:id media) + :deleted-at nil + :updated-at tnow} + {:file-id file-id + :object-id object-id + :tag tag})) + (db/insert! conn :file-tagged-object-thumbnail + {:file-id file-id + :object-id object-id + :created-at tnow + :updated-at tnow + :tag tag + :media-id (:id media)})))) -(def schema:create-file-object-thumbnail +(def ^:private + schema:create-file-object-thumbnail [:map {:title "create-file-object-thumbnail"} [:file-id ::sm/uuid] [:object-id :string] @@ -268,32 +289,37 @@ ::audit/skip true ::sm/params schema:create-file-object-thumbnail} - [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id object-id media tag]}] - (db/with-atomic [conn pool] - (files/check-edition-permissions! conn profile-id file-id) - (media/validate-media-type! media) - (media/validate-media-size! media) + [cfg {:keys [::rpc/profile-id file-id object-id media tag]}] + (db/tx-run! cfg + (fn [{:keys [::db/conn] :as cfg}] + (files/check-edition-permissions! conn profile-id file-id) + (media/validate-media-type! media) + (media/validate-media-size! media) - (when-not (db/read-only? conn) - (-> cfg - (update ::sto/storage media/configure-assets-storage) - (assoc ::db/conn conn) - (create-file-object-thumbnail! file-id object-id media (or tag "frame")))))) + (when-not (db/read-only? conn) + (let [cfg (-> cfg + (update ::sto/storage media/configure-assets-storage) + (assoc ::rtry/when rtry/conflict-exception?) + (assoc ::rtry/max-retries 5) + (assoc ::rtry/label "create-file-object-thumbnail"))] + (rtry/invoke cfg create-file-object-thumbnail! + file-id object-id media (or tag "frame"))))))) ;; --- MUTATION COMMAND: delete-file-object-thumbnail (defn- delete-file-object-thumbnail! [{:keys [::db/conn ::sto/storage]} file-id object-id] - (when-let [{:keys [media-id]} (db/get* conn :file-tagged-object-thumbnail - {:file-id file-id - :object-id object-id} - {::db/for-update? true})] - + (when-let [{:keys [media-id tag]} (db/get* conn :file-tagged-object-thumbnail + {:file-id file-id + :object-id object-id} + {::db/for-update? true})] (sto/touch-object! storage media-id) - (db/delete! conn :file-tagged-object-thumbnail + (db/update! conn :file-tagged-object-thumbnail + {:deleted-at (dt/now)} {:file-id file-id - :object-id object-id}) - nil)) + :object-id object-id + :tag tag} + {::db/return-keys? false}))) (s/def ::delete-file-object-thumbnail (s/keys :req [::rpc/profile-id] @@ -302,29 +328,21 @@ (sv/defmethod ::delete-file-object-thumbnail {::doc/added "1.19" ::doc/module :files + ::doc/deprecated "1.20" ::climit/id :file-thumbnail-ops ::climit/key-fn ::rpc/profile-id ::audit/skip true} - [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id object-id]}] - - (db/with-atomic [conn pool] - (files/check-edition-permissions! conn profile-id file-id) - - (when-not (db/read-only? conn) - (-> cfg - (update ::sto/storage media/configure-assets-storage) - (assoc ::db/conn conn) - (delete-file-object-thumbnail! file-id object-id)) - nil))) + [cfg {:keys [::rpc/profile-id file-id object-id]}] + (db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}] + (files/check-edition-permissions! conn profile-id file-id) + (when-not (db/read-only? conn) + (-> cfg + (update ::sto/storage media/configure-assets-storage conn) + (delete-file-object-thumbnail! file-id object-id)) + nil)))) ;; --- MUTATION COMMAND: create-file-thumbnail -(def ^:private sql:create-file-thumbnail - "insert into file_thumbnail (file_id, revn, media_id, props) - values (?, ?, ?, ?::jsonb) - on conflict(file_id, revn) do - update set media_id=?, props=?, updated_at=now();") - (defn- create-file-thumbnail! [{:keys [::db/conn ::sto/storage]} {:keys [file-id revn props media] :as params}] (media/validate-media-type! media) @@ -336,14 +354,42 @@ hash (sto/calculate-hash path) data (-> (sto/content path) (sto/wrap-with-hash hash)) + tnow (dt/now) media (sto/put-object! storage {::sto/content data - ::sto/deduplicate? false + ::sto/deduplicate? true + ::sto/touched-at tnow :content-type mtype - :bucket "file-thumbnail"})] - (db/exec-one! conn [sql:create-file-thumbnail file-id revn - (:id media) props - (:id media) props]) + :bucket "file-thumbnail"}) + + thumb (db/get* conn :file-thumbnail + {:file-id file-id + :revn revn} + {::db/remove-deleted? false + ::db/for-update? true})] + + (if (some? thumb) + (do + ;; We mark the old media id as touched if it does not match + (when (not= (:id media) (:media-id thumb)) + (sto/touch-object! storage (:media-id thumb))) + + (db/update! conn :file-thumbnail + {:media-id (:id media) + :deleted-at nil + :updated-at tnow + :props props} + {:file-id file-id + :revn revn})) + + (db/insert! conn :file-thumbnail + {:file-id file-id + :revn revn + :created-at tnow + :updated-at tnow + :props props + :media-id (:id media)})) + media)) (sv/defmethod ::create-file-thumbnail @@ -359,13 +405,14 @@ [:revn :int] [:media ::media/upload]]} - [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}] - (db/with-atomic [conn pool] - (files/check-edition-permissions! conn profile-id file-id) - (when-not (db/read-only? conn) - (let [media (-> cfg - (update ::sto/storage media/configure-assets-storage) - (assoc ::db/conn conn) - (create-file-thumbnail! params))] - - {:uri (files/resolve-public-uri (:id media))})))) + [cfg {:keys [::rpc/profile-id file-id] :as params}] + (db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}] + (files/check-edition-permissions! conn profile-id file-id) + (when-not (db/read-only? conn) + (let [cfg (-> cfg + (update ::sto/storage media/configure-assets-storage) + (assoc ::rtry/when rtry/conflict-exception?) + (assoc ::rtry/max-retries 5) + (assoc ::rtry/label "create-thumbnail")) + media (rtry/invoke cfg create-file-thumbnail! params)] + {:uri (files/resolve-public-uri (:id media))}))))) diff --git a/backend/src/app/rpc/commands/fonts.clj b/backend/src/app/rpc/commands/fonts.clj index 4fc55a77f9..830efe3e57 100644 --- a/backend/src/app/rpc/commands/fonts.clj +++ b/backend/src/app/rpc/commands/fonts.clj @@ -8,7 +8,7 @@ (:require [app.common.data.macros :as dm] [app.common.exceptions :as ex] - [app.common.spec :as us] + [app.common.schema :as sm] [app.common.uuid :as uuid] [app.db :as db] [app.loggers.audit :as-alias audit] @@ -25,39 +25,27 @@ [app.storage :as sto] [app.util.services :as sv] [app.util.time :as dt] - [app.worker :as-alias wrk] - [clojure.spec.alpha :as s])) + [app.worker :as-alias wrk])) (def valid-weight #{100 200 300 400 500 600 700 800 900 950}) (def valid-style #{"normal" "italic"}) -(s/def ::data (s/map-of ::us/string any?)) -(s/def ::file-id ::us/uuid) -(s/def ::font-id ::us/uuid) -(s/def ::id ::us/uuid) -(s/def ::name ::us/not-empty-string) -(s/def ::project-id ::us/uuid) -(s/def ::share-id ::us/uuid) -(s/def ::style valid-style) -(s/def ::team-id ::us/uuid) -(s/def ::weight valid-weight) - ;; --- QUERY: Get font variants -(s/def ::get-font-variants - (s/and - (s/keys :req [::rpc/profile-id] - :opt-un [::team-id - ::file-id - ::project-id - ::share-id]) - (fn [o] - (or (contains? o :team-id) - (contains? o :file-id) - (contains? o :project-id))))) +(def ^:private + schema:get-font-variants + [:schema {:title "get-font-variants"} + [:and + [:map + [:team-id {:optional true} ::sm/uuid] + [:file-id {:optional true} ::sm/uuid] + [:project-id {:optional true} ::sm/uuid] + [:share-id {:optional true} ::sm/uuid]] + [::sm/contains-any #{:team-id :file-id :project-id}]]]) (sv/defmethod ::get-font-variants - {::doc/added "1.18"} + {::doc/added "1.18" + ::sm/params schema:get-font-variants} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id team-id file-id project-id share-id] :as params}] (dm/with-open [conn (db/open pool)] (cond @@ -87,28 +75,31 @@ (declare create-font-variant) -(s/def ::create-font-variant - (s/keys :req [::rpc/profile-id] - :req-un [::team-id - ::data - ::font-id - ::font-family - ::font-weight - ::font-style])) +(def ^:private schema:create-font-variant + [:map {:title "create-font-variant"} + [:team-id ::sm/uuid] + [:data [:map-of :string :any]] + [:font-id ::sm/uuid] + [:font-family :string] + [:font-weight [::sm/one-of {:format "number"} valid-weight]] + [:font-style [::sm/one-of {:format "string"} valid-style]]]) (sv/defmethod ::create-font-variant {::doc/added "1.18" - ::webhooks/event? true} - [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id team-id] :as params}] - (let [cfg (update cfg ::sto/storage media/configure-assets-storage)] - (teams/check-edition-permissions! pool profile-id team-id) - (quotes/check-quote! pool {::quotes/id ::quotes/font-variants-per-team - ::quotes/profile-id profile-id - ::quotes/team-id team-id}) - (create-font-variant cfg (assoc params :profile-id profile-id)))) + ::webhooks/event? true + ::sm/params schema:create-font-variant} + [cfg {:keys [::rpc/profile-id team-id] :as params}] + (db/tx-run! cfg + (fn [{:keys [::db/conn] :as cfg}] + (let [cfg (update cfg ::sto/storage media/configure-assets-storage)] + (teams/check-edition-permissions! conn profile-id team-id) + (quotes/check-quote! conn {::quotes/id ::quotes/font-variants-per-team + ::quotes/profile-id profile-id + ::quotes/team-id team-id}) + (create-font-variant cfg (assoc params :profile-id profile-id)))))) (defn create-font-variant - [{:keys [::sto/storage ::db/pool] :as cfg} {:keys [data] :as params}] + [{:keys [::sto/storage ::db/conn] :as cfg} {:keys [data] :as params}] (letfn [(generate-missing! [data] (let [data (media/run {:cmd :generate-fonts :input data})] (when (and (not (contains? data "font/otf")) @@ -136,6 +127,7 @@ ttf-params (prepare-font data "font/ttf") wf1-params (prepare-font data "font/woff") wf2-params (prepare-font data "font/woff2")] + (cond-> {} (some? otf-params) (assoc :otf (sto/put-object! storage otf-params)) @@ -147,7 +139,7 @@ (assoc :woff2 (sto/put-object! storage wf2-params))))) (insert-font-variant! [{:keys [woff1 woff2 otf ttf]}] - (db/insert! pool :team-font-variant + (db/insert! conn :team-font-variant {:id (uuid/next) :team-id (:team-id params) :font-id (:font-id params) @@ -168,63 +160,109 @@ ;; --- UPDATE FONT FAMILY -(s/def ::update-font - (s/keys :req [::rpc/profile-id] - :req-un [::team-id ::id ::name])) +(def ^:private + schema:update-font + [:map {:title "update-font"} + [:team-id ::sm/uuid] + [:id ::sm/uuid] + [:name :string]]) (sv/defmethod ::update-font {::doc/added "1.18" - ::webhooks/event? true} - [{:keys [::db/pool]} {:keys [::rpc/profile-id team-id id name]}] - (db/with-atomic [conn pool] - (teams/check-edition-permissions! conn profile-id team-id) - (rph/with-meta - (db/update! conn :team-font-variant - {:font-family name} - {:font-id id - :team-id team-id}) - {::audit/replace-props {:id id - :name name - :team-id team-id - :profile-id profile-id}}))) + ::webhooks/event? true + ::sm/params schema:update-font} + [cfg {:keys [::rpc/profile-id team-id id name]}] + (db/tx-run! cfg + (fn [{:keys [::db/conn]}] + (teams/check-edition-permissions! conn profile-id team-id) + + (db/update! conn :team-font-variant + {:font-family name} + {:font-id id + :team-id team-id} + {::db/return-keys? false}) + + (rph/with-meta (rph/wrap nil) + {::audit/replace-props {:id id + :name name + :team-id team-id + :profile-id profile-id}})))) ;; --- DELETE FONT -(s/def ::delete-font - (s/keys :req [::rpc/profile-id] - :req-un [::team-id ::id])) +(def ^:private + schema:delete-font + [:map {:title "delete-font"} + [:team-id ::sm/uuid] + [:id ::sm/uuid]]) (sv/defmethod ::delete-font {::doc/added "1.18" - ::webhooks/event? true} - [{:keys [::db/pool]} {:keys [::rpc/profile-id id team-id]}] - (db/with-atomic [conn pool] - (teams/check-edition-permissions! conn profile-id team-id) - (let [font (db/update! conn :team-font-variant - {:deleted-at (dt/now)} - {:font-id id :team-id team-id})] - (rph/with-meta (rph/wrap) - {::audit/props {:id id - :team-id team-id - :name (:font-family font) - :profile-id profile-id}})))) + ::webhooks/event? true + ::sm/params schema:delete-font} + [cfg {:keys [::rpc/profile-id id team-id]}] + + (db/tx-run! cfg + (fn [{:keys [::db/conn ::sto/storage] :as cfg}] + (teams/check-edition-permissions! conn profile-id team-id) + (let [fonts (db/query conn :team-font-variant + {:team-id team-id + :font-id id + :deleted-at nil} + {::db/for-update? true}) + storage (media/configure-assets-storage storage conn) + tnow (dt/now)] + + (when-not (seq fonts) + (ex/raise :type :not-found + :code :object-not-found)) + + (doseq [font fonts] + (db/update! conn :team-font-variant + {:deleted-at tnow} + {:id (:id font)} + {::db/return-keys? false}) + (some->> (:woff1-file-id font) (sto/touch-object! storage)) + (some->> (:woff2-file-id font) (sto/touch-object! storage)) + (some->> (:ttf-file-id font) (sto/touch-object! storage)) + (some->> (:otf-file-id font) (sto/touch-object! storage))) + + (rph/with-meta (rph/wrap) + {::audit/props {:id id + :team-id team-id + :name (:font-family (peek fonts)) + :profile-id profile-id}}))))) ;; --- DELETE FONT VARIANT -(s/def ::delete-font-variant - (s/keys :req [::rpc/profile-id] - :req-un [::team-id ::id])) +(def ^:private schema:delete-font-variant + [:map {:title "delete-font-variant"} + [:team-id ::sm/uuid] + [:id ::sm/uuid]]) (sv/defmethod ::delete-font-variant {::doc/added "1.18" - ::webhooks/event? true} - [{:keys [::db/pool]} {:keys [::rpc/profile-id id team-id]}] - (db/with-atomic [conn pool] - (teams/check-edition-permissions! conn profile-id team-id) - (let [variant (db/update! conn :team-font-variant - {:deleted-at (dt/now)} - {:id id :team-id team-id})] - (rph/with-meta (rph/wrap) - {::audit/props {:font-family (:font-family variant) - :font-id (:font-id variant)}})))) + ::webhooks/event? true + ::sm/params schema:delete-font-variant} + [cfg {:keys [::rpc/profile-id id team-id]}] + (db/tx-run! cfg + (fn [{:keys [::db/conn ::sto/storage] :as cfg}] + (teams/check-edition-permissions! conn profile-id team-id) + (let [variant (db/get conn :team-font-variant + {:id id :team-id team-id} + {::db/for-update? true}) + storage (media/configure-assets-storage storage conn)] + (db/update! conn :team-font-variant + {:deleted-at (dt/now)} + {:id (:id variant)} + {::db/return-keys? false}) + + (some->> (:woff1-file-id variant) (sto/touch-object! storage)) + (some->> (:woff2-file-id variant) (sto/touch-object! storage)) + (some->> (:ttf-file-id variant) (sto/touch-object! storage)) + (some->> (:otf-file-id variant) (sto/touch-object! storage)) + + (rph/with-meta (rph/wrap) + {::audit/props {:font-family (:font-family variant) + :font-id (:font-id variant)}}))))) diff --git a/backend/src/app/rpc/commands/media.clj b/backend/src/app/rpc/commands/media.clj index 04ad8bc9bc..a357c109c2 100644 --- a/backend/src/app/rpc/commands/media.clj +++ b/backend/src/app/rpc/commands/media.clj @@ -23,6 +23,7 @@ [app.storage :as sto] [app.storage.tmp :as tmp] [app.util.services :as sv] + [app.util.time :as dt] [app.worker :as-alias wrk] [clojure.spec.alpha :as s] [cuerdas.core :as str] @@ -153,6 +154,12 @@ thumb (when-let [params (::thumb result)] (sto/put-object! storage params))] + (db/update! conn :file + {:modified-at (dt/now) + :has-media-trimmed false} + {:id file-id} + {::db/return-keys? false}) + (db/exec-one! conn [sql:create-file-media-object (or id (uuid/next)) file-id is-local name diff --git a/backend/src/app/rpc/retry.clj b/backend/src/app/rpc/retry.clj index 9cb048ea91..bd9c3ea075 100644 --- a/backend/src/app/rpc/retry.clj +++ b/backend/src/app/rpc/retry.clj @@ -18,46 +18,47 @@ (and (instance? PSQLException e) (= "23505" (.getSQLState ^PSQLException e)))) -(def ^:private always-false (constantly false)) +(def ^:private always-false + (constantly false)) (defn wrap-retry - [_ f {:keys [::matches ::sv/name] :or {matches always-false} :as mdata}] + [_ f {:keys [::sv/name] :as mdata}] - (when (::enabled mdata) - (l/debug :hint "wrapping retry" :name name)) - - (if-let [max-retries (::max-retries mdata)] - (fn [cfg params] - ((fn run [retry] - (try - (f cfg params) - (catch Throwable cause - (if (matches cause) - (let [current-retry (inc retry)] - (l/trace :hint "running retry algorithm" :retry current-retry) - (if (<= current-retry max-retries) - (run current-retry) - (throw cause))) - (throw cause))))) 1)) + (if (::enabled mdata) + (let [max-retries (get mdata ::max-retries 3) + matches? (get mdata ::when always-false)] + (l/dbg :hint "wrapping retry" :name name :max-retries max-retries) + (fn [cfg params] + ((fn recursive-invoke [retry] + (try + (f cfg params) + (catch Throwable cause + (if (matches? cause) + (let [current-retry (inc retry)] + (l/wrn :hint "retrying operation" :retry current-retry :service name) + (if (<= current-retry max-retries) + (recursive-invoke current-retry) + (throw cause))) + (throw cause))))) 1))) f)) -(defmacro with-retry - [{:keys [::when ::max-retries ::label ::db/conn] :or {max-retries 3}} & body] - `(let [conn# ~conn] - (assert (or (nil? conn#) (db/connection? conn#)) "invalid database connection") - (loop [tnum# 1] - (let [result# (let [sp# (some-> conn# db/savepoint)] - (try - (let [result# (do ~@body)] - (some->> sp# (db/release! conn#)) - result#) - (catch Throwable cause# - (some->> sp# (db/rollback! conn#)) - (if (and (~when cause#) (<= tnum# ~max-retries)) - ::retry - (throw cause#)))))] - (if (= ::retry result#) - (do - (l/warn :hint "retrying operation" :label ~label :retry tnum#) - (recur (inc tnum#))) - result#))))) +(defn invoke + [{:keys [::db/conn ::max-retries] :or {max-retries 3} :as cfg} f & args] + (assert (db/connection? conn) "invalid database connection") + (loop [rnum 1] + (let [match? (get cfg ::when always-false) + result (let [spoint (db/savepoint conn)] + (try + (let [result (apply f cfg args)] + (db/release! conn spoint) + result) + (catch Throwable cause + (db/rollback! conn spoint) + (if (and (match? cause) (<= rnum max-retries)) + ::retry + (throw cause)))))] + (if (= ::retry result) + (let [label (get cfg ::label "anonymous")] + (l/warn :hint "retrying operation" :label label :retry rnum) + (recur (inc rnum))) + result)))) diff --git a/backend/src/app/storage.clj b/backend/src/app/storage.clj index 299fefcbb0..5d24f8e688 100644 --- a/backend/src/app/storage.clj +++ b/backend/src/app/storage.clj @@ -9,8 +9,6 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.exceptions :as ex] - [app.common.logging :as l] [app.common.spec :as us] [app.common.uuid :as uuid] [app.db :as db] @@ -228,225 +226,3 @@ (dm/export impl/resolve-backend) (dm/export impl/calculate-hash) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Garbage Collection: Permanently delete objects -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A task responsible to permanently delete already marked as deleted -;; storage files. The storage objects are practically never marked to -;; be deleted directly by the api call. The touched-gc is responsible -;; of collecting the usage of the object and mark it as deleted. Only -;; the TMP files are are created with expiration date in future. - -(declare sql:retrieve-deleted-objects-chunk) - -(defmethod ig/pre-init-spec ::gc-deleted-task [_] - (s/keys :req [::storage ::db/pool])) - -(defmethod ig/prep-key ::gc-deleted-task - [_ cfg] - (assoc cfg ::min-age (dt/duration {:hours 2}))) - -(defmethod ig/init-key ::gc-deleted-task - [_ {:keys [::db/pool ::storage ::min-age]}] - (letfn [(get-to-delete-chunk [cursor] - (let [sql (str "select s.* " - " from storage_object as s " - " where s.deleted_at is not null " - " and s.deleted_at < ? " - " order by s.deleted_at desc " - " limit 25") - rows (db/exec! pool [sql cursor])] - [(some-> rows peek :deleted-at) - (some->> (seq rows) (d/group-by #(-> % :backend keyword) :id #{}) seq)])) - - (get-to-delete-chunks [min-age] - (d/iteration get-to-delete-chunk - :initk (dt/minus (dt/now) min-age) - :vf second - :kf first)) - - (delete-in-bulk! [backend-id ids] - (try - (db/with-atomic [conn pool] - (let [sql "delete from storage_object where id = ANY(?)" - ids' (db/create-array conn "uuid" ids) - - total (-> (db/exec-one! conn [sql ids']) - (db/get-update-count))] - - (-> (impl/resolve-backend storage backend-id) - (impl/del-objects-in-bulk ids)) - - (doseq [id ids] - (l/dbg :hint "gc-deleted: permanently delete storage object" :backend backend-id :id id)) - - total)) - - (catch Throwable cause - (l/err :hint "gc-deleted: unexpected error on bulk deletion" - :ids (vec ids) - :cause cause) - 0)))] - - (fn [params] - (let [min-age (or (some-> params :min-age dt/duration) min-age)] - (loop [total 0 - chunks (get-to-delete-chunks min-age)] - (if-let [[backend-id ids] (first chunks)] - (let [deleted (delete-in-bulk! backend-id ids)] - (recur (+ total deleted) - (rest chunks))) - (do - (l/inf :hint "gc-deleted: task finished" - :min-age (dt/format-duration min-age) - :total total) - {:deleted total}))))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Garbage Collection: Analyze touched objects -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; This task is part of the garbage collection process of storage -;; objects and is responsible on analyzing the touched objects and -;; mark them for deletion if corresponds. -;; -;; For example: when file_media_object is deleted, the depending -;; storage_object are marked as touched. This means that some files -;; that depend on a concrete storage_object are no longer exists and -;; maybe this storage_object is no longer necessary and can be -;; eligible for elimination. This task periodically analyzes touched -;; objects and mark them as freeze (means that has other references -;; and the object is still valid) or deleted (no more references to -;; this object so is ready to be deleted). - -(declare sql:retrieve-file-media-object-nrefs) -(declare sql:retrieve-file-object-thumbnail-nrefs) -(declare sql:retrieve-profile-nrefs) -(declare sql:retrieve-team-font-variant-nrefs) -(declare sql:retrieve-touched-objects-chunk) - -(defmethod ig/pre-init-spec ::gc-touched-task [_] - (s/keys :req [::db/pool])) - -(defmethod ig/init-key ::gc-touched-task - [_ {:keys [::db/pool]}] - (letfn [(get-team-font-variant-nrefs [conn id] - (-> (db/exec-one! conn [sql:retrieve-team-font-variant-nrefs id id id id]) :nrefs)) - - (get-file-media-object-nrefs [conn id] - (-> (db/exec-one! conn [sql:retrieve-file-media-object-nrefs id id]) :nrefs)) - - (get-profile-nrefs [conn id] - (-> (db/exec-one! conn [sql:retrieve-profile-nrefs id id]) :nrefs)) - - (get-file-object-thumbnails [conn id] - (-> (db/exec-one! conn [sql:retrieve-file-object-thumbnail-nrefs id]) :nrefs)) - - (mark-freeze-in-bulk [conn ids] - (db/exec-one! conn ["update storage_object set touched_at=null where id = ANY(?)" - (db/create-array conn "uuid" ids)])) - - (mark-delete-in-bulk [conn ids] - (db/exec-one! conn ["update storage_object set deleted_at=now(), touched_at=null where id = ANY(?)" - (db/create-array conn "uuid" ids)])) - - ;; NOTE: A getter that retrieves the key witch will be used - ;; for group ids; previously we have no value, then we - ;; introduced the `:reference` prop, and then it is renamed - ;; to `:bucket` and now is string instead. This is - ;; implemented in this way for backward comaptibilty. - - ;; NOTE: we use the "file-media-object" as default value for - ;; backward compatibility because when we deploy it we can - ;; have old backend instances running in the same time as - ;; the new one and we can still have storage-objects created - ;; without bucket value. And we know that if it does not - ;; have value, it means :file-media-object. - - (get-bucket [{:keys [metadata]}] - (or (some-> metadata :bucket) - (some-> metadata :reference d/name) - "file-media-object")) - - (retrieve-touched-chunk [conn cursor] - (let [rows (->> (db/exec! conn [sql:retrieve-touched-objects-chunk cursor]) - (mapv #(d/update-when % :metadata db/decode-transit-pgobject)))] - (when (seq rows) - [(-> rows peek :created-at) - (d/group-by get-bucket :id #{} rows)]))) - - (retrieve-touched [conn] - (d/iteration (partial retrieve-touched-chunk conn) - :initk (dt/now) - :vf second - :kf first)) - - (process-objects! [conn get-fn ids bucket] - (loop [to-freeze #{} - to-delete #{} - ids (seq ids)] - (if-let [id (first ids)] - (let [nrefs (get-fn conn id)] - (if (pos? nrefs) - (do - (l/debug :hint "gc-touched: processing storage object" - :id id :status "freeze" - :bucket bucket :refs nrefs) - (recur (conj to-freeze id) to-delete (rest ids))) - (do - (l/debug :hint "gc-touched: processing storage object" - :id id :status "delete" - :bucket bucket :refs nrefs) - (recur to-freeze (conj to-delete id) (rest ids))))) - (do - (some->> (seq to-freeze) (mark-freeze-in-bulk conn)) - (some->> (seq to-delete) (mark-delete-in-bulk conn)) - [(count to-freeze) (count to-delete)]))))] - - (fn [_] - (db/with-atomic [conn pool] - (loop [to-freeze 0 - to-delete 0 - groups (retrieve-touched conn)] - (if-let [[bucket ids] (first groups)] - (let [[f d] (case bucket - "file-media-object" (process-objects! conn get-file-media-object-nrefs ids bucket) - "team-font-variant" (process-objects! conn get-team-font-variant-nrefs ids bucket) - "file-object-thumbnail" (process-objects! conn get-file-object-thumbnails ids bucket) - "profile" (process-objects! conn get-profile-nrefs ids bucket) - (ex/raise :type :internal - :code :unexpected-unknown-reference - :hint (dm/fmt "unknown reference %" bucket)))] - (recur (+ to-freeze (long f)) - (+ to-delete (long d)) - (rest groups))) - (do - (l/info :hint "gc-touched: task finished" :to-freeze to-freeze :to-delete to-delete) - {:freeze to-freeze :delete to-delete}))))))) - -(def sql:retrieve-touched-objects-chunk - "SELECT so.* - FROM storage_object AS so - WHERE so.touched_at IS NOT NULL - AND so.created_at < ? - ORDER by so.created_at DESC - LIMIT 500;") - -(def sql:retrieve-file-media-object-nrefs - "select ((select count(*) from file_media_object where media_id = ?) + - (select count(*) from file_media_object where thumbnail_id = ?)) as nrefs") - -(def sql:retrieve-file-object-thumbnail-nrefs - "select (select count(*) from file_tagged_object_thumbnail where media_id = ?) as nrefs") - -(def sql:retrieve-team-font-variant-nrefs - "select ((select count(*) from team_font_variant where woff1_file_id = ?) + - (select count(*) from team_font_variant where woff2_file_id = ?) + - (select count(*) from team_font_variant where otf_file_id = ?) + - (select count(*) from team_font_variant where ttf_file_id = ?)) as nrefs") - -(def sql:retrieve-profile-nrefs - "select ((select count(*) from profile where photo_id = ?) + - (select count(*) from team where photo_id = ?)) as nrefs") diff --git a/backend/src/app/storage/gc_deleted.clj b/backend/src/app/storage/gc_deleted.clj new file mode 100644 index 0000000000..ec90d483fe --- /dev/null +++ b/backend/src/app/storage/gc_deleted.clj @@ -0,0 +1,128 @@ +;; 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.storage.gc-deleted + "A task responsible to permanently delete already marked as deleted + storage files. The storage objects are practically never marked to + be deleted directly by the api call. + + The touched-gc is responsible of collecting the usage of the object + and mark it as deleted. Only the TMP files are are created with + expiration date in future." + (:require + [app.common.data :as d] + [app.common.logging :as l] + [app.db :as db] + [app.storage :as-alias sto] + [app.storage.impl :as impl] + [app.util.time :as dt] + [clojure.spec.alpha :as s] + [integrant.core :as ig])) + +(def ^:private sql:lock-sobjects + "SELECT id FROM storage_object + WHERE id = ANY(?::uuid[]) + FOR UPDATE + SKIP LOCKED") + +(defn- lock-ids + "Perform a select before delete for proper object locking and + prevent concurrent operations and we proceed only with successfully + locked objects." + [conn ids] + (let [ids (db/create-array conn "uuid" ids)] + (->> (db/exec! conn [sql:lock-sobjects ids]) + (into #{} (map :id)) + (not-empty)))) + + +(def ^:private sql:delete-sobjects + "DELETE FROM storage_object + WHERE id = ANY(?::uuid[])") + +(defn- delete-sobjects! + [conn ids] + (let [ids (db/create-array conn "uuid" ids)] + (-> (db/exec-one! conn [sql:delete-sobjects ids]) + (db/get-update-count)))) + + +(defn- delete-in-bulk! + [cfg backend-id ids] + ;; We run the deletion on a separate transaction. This is + ;; because if some exception is raised inside procesing + ;; one chunk, it does not affects the rest of the chunks. + (try + (db/tx-run! cfg + (fn [{:keys [::db/conn ::sto/storage]}] + (when-let [ids (lock-ids conn ids)] + (let [total (delete-sobjects! conn ids)] + + (-> (impl/resolve-backend storage backend-id) + (impl/del-objects-in-bulk ids)) + + (doseq [id ids] + (l/dbg :hint "permanently delete storage object" + :id (str id) + :backend (name backend-id))) + + total)))) + (catch Throwable cause + (l/err :hint "unexpected error on bulk deletion" + :ids ids + :cause cause)))) + + +(defn- group-by-backend + [items] + (d/group-by (comp keyword :backend) :id #{} items)) + +(def ^:private sql:get-deleted-sobjects + "SELECT s.* FROM storage_object AS s + WHERE s.deleted_at IS NOT NULL + AND s.deleted_at < now() - ?::interval + ORDER BY s.deleted_at ASC") + +(defn- get-buckets + [conn min-age] + (let [age (db/interval min-age)] + (sequence + (comp (partition-all 25) + (mapcat group-by-backend)) + (db/cursor conn [sql:get-deleted-sobjects age])))) + + +(defn- clean-deleted! + [{:keys [::db/conn ::min-age] :as cfg}] + (reduce (fn [total [backend-id ids]] + (let [deleted (delete-in-bulk! cfg backend-id ids)] + (+ total (or deleted 0)))) + 0 + (get-buckets conn min-age))) + + +(defmethod ig/pre-init-spec ::handler [_] + (s/keys :req [::sto/storage ::db/pool])) + +(defmethod ig/prep-key ::handler + [_ cfg] + (assoc cfg ::min-age (dt/duration {:hours 2}))) + +(defmethod ig/init-key ::handler + [_ {:keys [::min-age] :as cfg}] + (fn [params] + (let [min-age (dt/duration (or (:min-age params) min-age))] + (db/tx-run! cfg (fn [cfg] + (let [cfg (assoc cfg ::min-age min-age) + total (clean-deleted! cfg)] + + (l/inf :hint "task finished" + :min-age (dt/format-duration min-age) + :total total) + + {:deleted total})))))) + + diff --git a/backend/src/app/storage/gc_touched.clj b/backend/src/app/storage/gc_touched.clj new file mode 100644 index 0000000000..bd499bb655 --- /dev/null +++ b/backend/src/app/storage/gc_touched.clj @@ -0,0 +1,208 @@ +;; 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.storage.gc-touched + "This task is part of the garbage collection process of storage + objects and is responsible on analyzing the touched objects and mark + them for deletion if corresponds. + + For example: when file_media_object is deleted, the depending + storage_object are marked as touched. This means that some files + that depend on a concrete storage_object are no longer exists and + maybe this storage_object is no longer necessary and can be eligible + for elimination. This task periodically analyzes touched objects and + mark them as freeze (means that has other references and the object + is still valid) or deleted (no more references to this object so is + ready to be deleted)." + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.exceptions :as ex] + [app.common.logging :as l] + [app.db :as db] + [app.storage :as-alias sto] + [app.storage.impl :as impl] + [clojure.spec.alpha :as s] + [integrant.core :as ig])) + +(def ^:private sql:get-team-font-variant-nrefs + "SELECT ((SELECT count(*) FROM team_font_variant WHERE woff1_file_id = ?) + + (SELECT count(*) FROM team_font_variant WHERE woff2_file_id = ?) + + (SELECT count(*) FROM team_font_variant WHERE otf_file_id = ?) + + (SELECT count(*) FROM team_font_variant WHERE ttf_file_id = ?)) AS nrefs") + +(defn- get-team-font-variant-nrefs + [conn id] + (-> (db/exec-one! conn [sql:get-team-font-variant-nrefs id id id id]) + (get :nrefs))) + + +(def ^:private + sql:get-file-media-object-nrefs + "SELECT ((SELECT count(*) FROM file_media_object WHERE media_id = ?) + + (SELECT count(*) FROM file_media_object WHERE thumbnail_id = ?)) AS nrefs") + +(defn- get-file-media-object-nrefs + [conn id] + (-> (db/exec-one! conn [sql:get-file-media-object-nrefs id id]) + (get :nrefs))) + + +(def ^:private sql:get-profile-nrefs + "SELECT ((SELECT count(*) FROM profile WHERE photo_id = ?) + + (SELECT count(*) FROM team WHERE photo_id = ?)) AS nrefs") + +(defn- get-profile-nrefs + [conn id] + (-> (db/exec-one! conn [sql:get-profile-nrefs id id]) + (get :nrefs))) + + +(def ^:private + sql:get-file-object-thumbnail-nrefs + "SELECT (SELECT count(*) FROM file_tagged_object_thumbnail WHERE media_id = ?) AS nrefs") + +(defn- get-file-object-thumbnails + [conn id] + (-> (db/exec-one! conn [sql:get-file-object-thumbnail-nrefs id]) + (get :nrefs))) + + +(def ^:private + sql:get-file-thumbnail-nrefs + "SELECT (SELECT count(*) FROM file_thumbnail WHERE media_id = ?) AS nrefs") + +(defn- get-file-thumbnails + [conn id] + (-> (db/exec-one! conn [sql:get-file-thumbnail-nrefs id]) + (get :nrefs))) + + +(def ^:private sql:mark-freeze-in-bulk + "UPDATE storage_object + SET touched_at = NULL + WHERE id = ANY(?::uuid[])") + +(defn- mark-freeze-in-bulk! + [conn ids] + (let [ids (db/create-array conn "uuid" ids)] + (db/exec-one! conn [sql:mark-freeze-in-bulk ids]))) + + +(def ^:private sql:mark-delete-in-bulk + "UPDATE storage_object + SET deleted_at = now(), + touched_at = NULL + WHERE id = ANY(?::uuid[])") + +(defn- mark-delete-in-bulk! + [conn ids] + (let [ids (db/create-array conn "uuid" ids)] + (db/exec-one! conn [sql:mark-delete-in-bulk ids]))) + +;; NOTE: A getter that retrieves the key which will be used for group +;; ids; previously we have no value, then we introduced the +;; `:reference` prop, and then it is renamed to `:bucket` and now is +;; string instead. This is implemented in this way for backward +;; comaptibilty. + +;; NOTE: we use the "file-media-object" as default value for +;; backward compatibility because when we deploy it we can +;; have old backend instances running in the same time as +;; the new one and we can still have storage-objects created +;; without bucket value. And we know that if it does not +;; have value, it means :file-media-object. + +(defn- lookup-bucket + [{:keys [metadata]}] + (or (some-> metadata :bucket) + (some-> metadata :reference d/name) + "file-media-object")) + +(defn- process-objects! + [conn get-fn ids bucket] + (loop [to-freeze #{} + to-delete #{} + ids (seq ids)] + (if-let [id (first ids)] + (let [nrefs (get-fn conn id)] + (if (pos? nrefs) + (do + (l/debug :hint "processing object" + :id (str id) + :status "freeze" + :bucket bucket :refs nrefs) + (recur (conj to-freeze id) to-delete (rest ids))) + (do + (l/debug :hint "processing object" + :id (str id) + :status "delete" + :bucket bucket :refs nrefs) + (recur to-freeze (conj to-delete id) (rest ids))))) + (do + (some->> (seq to-freeze) (mark-freeze-in-bulk! conn)) + (some->> (seq to-delete) (mark-delete-in-bulk! conn)) + [(count to-freeze) (count to-delete)])))) + +(defn- process-bucket! + [conn bucket ids] + (case bucket + "file-media-object" (process-objects! conn get-file-media-object-nrefs ids bucket) + "team-font-variant" (process-objects! conn get-team-font-variant-nrefs ids bucket) + "file-object-thumbnail" (process-objects! conn get-file-object-thumbnails ids bucket) + "file-thumbnail" (process-objects! conn get-file-thumbnails ids bucket) + "profile" (process-objects! conn get-profile-nrefs ids bucket) + (ex/raise :type :internal + :code :unexpected-unknown-reference + :hint (dm/fmt "unknown reference %" bucket)))) + + +(def ^:private + sql:get-touched-storage-objects + "SELECT so.* + FROM storage_object AS so + WHERE so.touched_at IS NOT NULL + ORDER BY touched_at ASC + FOR UPDATE + SKIP LOCKED") + +(defn- group-by-bucket + [row] + (d/group-by lookup-bucket :id #{} row)) + +(defn- get-buckets + [conn] + (sequence + (comp (map impl/decode-row) + (partition-all 25) + (mapcat group-by-bucket)) + (db/cursor conn sql:get-touched-storage-objects))) + +(defn- process-touched! + [{:keys [::db/conn]}] + (loop [buckets (get-buckets conn) + freezed 0 + deleted 0] + (if-let [[bucket ids] (first buckets)] + (let [[nfo ndo] (process-bucket! conn bucket ids)] + (recur (rest buckets) + (+ freezed nfo) + (+ deleted ndo))) + (do + (l/inf :hint "task finished" + :to-freeze freezed + :to-delete deleted) + + {:freeze freezed :delete deleted})))) + +(defmethod ig/pre-init-spec ::handler [_] + (s/keys :req [::db/pool])) + +(defmethod ig/init-key ::handler + [_ cfg] + (fn [_] + (db/tx-run! cfg process-touched!))) + diff --git a/backend/src/app/storage/impl.clj b/backend/src/app/storage/impl.clj index 9dc7facc14..156d86b872 100644 --- a/backend/src/app/storage/impl.clj +++ b/backend/src/app/storage/impl.clj @@ -9,7 +9,7 @@ (:require [app.common.data.macros :as dm] [app.common.exceptions :as ex] - [app.db :as-alias db] + [app.db :as db] [app.storage :as-alias sto] [buddy.core.codecs :as bc] [buddy.core.hash :as bh] @@ -22,6 +22,13 @@ java.nio.file.Path java.util.UUID)) +(defn decode-row + "Decode the storage-object row fields" + [{:keys [metadata] :as row}] + (cond-> row + (some? metadata) + (assoc :metadata (db/decode-transit-pgobject metadata)))) + ;; --- API Definition (defmulti put-object (fn [cfg _ _] (::sto/type cfg))) diff --git a/backend/src/app/tasks/file_gc.clj b/backend/src/app/tasks/file_gc.clj index 5e97bdabc0..3e75cb728e 100644 --- a/backend/src/app/tasks/file_gc.clj +++ b/backend/src/app/tasks/file_gc.clj @@ -10,7 +10,6 @@ file is eligible to be garbage collected after some period of inactivity (the default threshold is 72h)." (:require - [app.common.data :as d] [app.common.files.migrations :as pmg] [app.common.logging :as l] [app.common.thumbnails :as thc] @@ -30,7 +29,7 @@ [integrant.core :as ig])) (declare ^:private get-candidates) -(declare ^:private process-file) +(declare ^:private clean-file!) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; HANDLER @@ -44,67 +43,61 @@ (assoc cfg ::min-age cf/deletion-delay)) (defmethod ig/init-key ::handler - [_ {:keys [::db/pool] :as cfg}] + [_ cfg] (fn [{:keys [file-id] :as params}] + (db/tx-run! cfg + (fn [{:keys [::db/conn] :as cfg}] + (let [min-age (dt/duration (or (:min-age params) (::min-age cfg))) + cfg (-> cfg + (update ::sto/storage media/configure-assets-storage conn) + (assoc ::file-id file-id) + (assoc ::min-age min-age)) - (db/with-atomic [conn pool] - (let [min-age (dt/duration (or (:min-age params) (::min-age cfg))) - cfg (-> cfg - (update ::sto/storage media/configure-assets-storage conn) - (assoc ::db/conn conn) - (assoc ::file-id file-id) - (assoc ::min-age min-age)) + total (reduce (fn [total file] + (clean-file! cfg file) + (inc total)) + 0 + (get-candidates cfg))] - total (reduce (fn [total file] - (process-file cfg file) - (inc total)) - 0 - (get-candidates cfg))] + (l/inf :hint "task finished" + :min-age (dt/format-duration min-age) + :processed total) - (l/info :hint "task finished" :min-age (dt/format-duration min-age) :processed total) + ;; Allow optional rollback passed by params + (when (:rollback? params) + (db/rollback! conn)) - ;; Allow optional rollback passed by params - (when (:rollback? params) - (db/rollback! conn)) - - {:processed total})))) + {:processed total}))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; IMPL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (def ^:private - sql:get-candidates-chunk - "select f.id, + sql:get-candidates + "SELECT f.id, f.data, f.revn, f.features, f.modified_at - from file as f - where f.has_media_trimmed is false - and f.modified_at < now() - ?::interval - and f.modified_at < ? - order by f.modified_at desc - limit 1 - for update skip locked") + FROM file AS f + WHERE f.has_media_trimmed IS false + AND f.modified_at < now() - ?::interval + ORDER BY f.modified_at DESC + FOR UPDATE + SKIP LOCKED") (defn- get-candidates [{:keys [::db/conn ::min-age ::file-id]}] (if (uuid? file-id) (do - (l/warn :hint "explicit file id passed on params" :file-id file-id) + (l/warn :hint "explicit file id passed on params" :file-id (str file-id)) (->> (db/query conn :file {:id file-id}) (map #(update % :features db/decode-pgarray #{})))) - (let [interval (db/interval min-age) - get-chunk (fn [cursor] - (let [rows (db/exec! conn [sql:get-candidates-chunk interval cursor])] - [(some->> rows peek :modified-at) - (map #(update % :features db/decode-pgarray #{}) rows)]))] - (d/iteration get-chunk - :vf second - :kf first - :initk (dt/now))))) + (let [min-age (db/interval min-age)] + (->> (db/cursor conn [sql:get-candidates min-age] {:chunk-size 1}) + (map #(update % :features db/decode-pgarray #{})))))) (defn collect-used-media "Given a fdata (file data), returns all media references." @@ -134,101 +127,93 @@ (into xform pages) (into (keys (:media data)))))) + +(def ^:private sql:mark-file-media-object-deleted + "UPDATE file_media_object + SET deleted_at = now() + WHERE file_id = ? AND id != ALL(?::uuid[]) + RETURNING id") + (defn- clean-file-media! "Performs the garbage collection of file media objects." [conn file-id data] (let [used (collect-used-media data) - unused (->> (db/query conn :file-media-object {:file-id file-id}) - (remove #(contains? used (:id %))))] + ids (db/create-array conn "uuid" used) + unused (->> (db/exec! conn [sql:mark-file-media-object-deleted file-id ids]) + (into #{} (map :id)))] - (doseq [mobj unused] - (l/dbg :hint "delete file media object" - :id (:id mobj) - :media-id (:media-id mobj) - :thumbnail-id (:thumbnail-id mobj)) + (doseq [id unused] + (l/trc :hint "mark deleted" + :rel "file-media-object" + :id (str id) + :file-id (str file-id))) - ;; NOTE: deleting the file-media-object in the database - ;; automatically marks as touched the referenced storage - ;; objects. The touch mechanism is needed because many files can - ;; point to the same storage objects and we can't just delete - ;; them. - (db/delete! conn :file-media-object {:id (:id mobj)})))) + (count unused))) + + +(def ^:private sql:mark-file-object-thumbnails-deleted + "UPDATE file_tagged_object_thumbnail + SET deleted_at = now() + WHERE file_id = ? AND object_id != ALL(?::text[]) + RETURNING object_id") (defn- clean-file-object-thumbnails! - [{:keys [::db/conn ::sto/storage]} file-id data] - (let [stored (->> (db/query conn :file-tagged-object-thumbnail - {:file-id file-id} - {:columns [:object-id]}) - (into #{} (map :object-id))) + [{:keys [::db/conn]} file-id data] + (let [using (->> (vals (:pages-index data)) + (into #{} (comp + (mapcat (fn [{:keys [id objects]}] + (->> (ctt/get-frames objects) + (map #(assoc % :page-id id))))) + (mapcat (fn [{:keys [id page-id]}] + (list + (thc/fmt-object-id file-id page-id id "frame") + (thc/fmt-object-id file-id page-id id "component"))))))) - using (into #{} - (comp - (mapcat (fn [{:keys [id objects]}] - (->> (ctt/get-frames objects) - (map #(assoc % :page-id id))))) - (mapcat (fn [{:keys [id page-id]}] - (list - (thc/fmt-object-id file-id page-id id "frame") - (thc/fmt-object-id file-id page-id id "component"))))) + ids (db/create-array conn "text" using) + unused (->> (db/exec! conn [sql:mark-file-object-thumbnails-deleted file-id ids]) + (into #{} (map :object-id)))] - (vals (:pages-index data))) + (doseq [object-id unused] + (l/trc :hint "mark deleted" + :rel "file-tagged-object-thumbnail" + :object-id object-id + :file-id (str file-id))) - unused (set/difference stored using)] + (count unused))) - (when (seq unused) - (let [sql (str "delete from file_tagged_object_thumbnail " - " where file_id=? and object_id=ANY(?)" - " returning media_id") - res (db/exec! conn [sql file-id (db/create-array conn "text" unused)])] - (l/dbg :hint "delete file object thumbnails" - :file-id (str file-id) - :total (count res)) - - (doseq [media-id (into #{} (keep :media-id) res)] - ;; Mark as deleted the storage object related with the - ;; photo-id field. - (l/trc :hint "touch file object thumbnail storage object" :id (str media-id)) - (sto/touch-object! storage media-id)))))) +(def ^:private sql:mark-file-thumbnails-deleted + "UPDATE file_thumbnail + SET deleted_at = now() + WHERE file_id = ? AND revn < ? + RETURNING revn") (defn- clean-file-thumbnails! - [{:keys [::db/conn ::sto/storage]} file-id revn] - (let [sql (str "delete from file_thumbnail " - " where file_id=? and revn < ? " - " returning media_id") - res (db/exec! conn [sql file-id revn])] + [{:keys [::db/conn]} file-id revn] + (let [unused (->> (db/exec! conn [sql:mark-file-thumbnails-deleted file-id revn]) + (into #{} (map :revn)))] - (when (seq res) - (l/dbg :hint "delete file thumbnails" - :file-id (str file-id) - :total (count res)) + (doseq [revn unused] + (l/trc :hint "mark deleted" + :rel "file-thumbnail" + :revn revn + :file-id (str file-id))) - (doseq [media-id (into #{} (keep :media-id) res)] - ;; Mark as deleted the storage object related with the - ;; media-id field. - (l/trc :hint "delete file thumbnail storage object" :id (str media-id)) - (sto/del-object! storage media-id))))) + (count unused))) -(def ^:private - sql:get-files-for-library - "select f.data, f.modified_at - from file as f - left join file_library_rel as fl on (fl.file_id = f.id) - where fl.library_file_id = ? - and f.modified_at < ? - and f.deleted_at is null - order by f.modified_at desc - limit 1") + +(def ^:private sql:get-files-for-library + "SELECT f.id, f.data, f.modified_at + FROM file AS f + LEFT JOIN file_library_rel AS fl ON (fl.file_id = f.id) + WHERE fl.library_file_id = ? + AND f.deleted_at IS null + ORDER BY f.modified_at ASC") (defn- clean-deleted-components! "Performs the garbage collection of unreferenced deleted components." - [conn file-id data] - (letfn [(get-files-chunk [cursor] - (let [rows (db/exec! conn [sql:get-files-for-library file-id cursor])] - [(some-> rows peek :modified-at) - (map (comp blob/decode :data) rows)])) - - (get-used-components [fdata components] + [{:keys [::db/conn] :as cfg} file-id data] + (letfn [(get-used-components [fdata components] ;; Find which of the components are used in the file. (into #{} (filter #(ctf/used-in? fdata file-id % :component)) @@ -246,69 +231,91 @@ files-data))] (let [deleted (into #{} (ctkl/deleted-components-seq data)) - unused (->> (d/iteration get-files-chunk :vf second :kf first :initk (dt/now)) + unused (->> (db/cursor conn [sql:get-files-for-library file-id] {:chunk-size 1}) + (map (fn [{:keys [id data] :as file}] + (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)] + (-> (blob/decode data) + (feat.fdata/process-pointers deref))))) (cons data) (get-unused-components deleted) (mapv :id))] - (when (seq unused) - (l/dbg :hint "clean deleted components" :total (count unused)) + (doseq [id unused] + (l/trc :hint "delete component" :component-id (str id) :file-id (str file-id))) - (let [data (reduce ctkl/delete-component data unused)] - (db/update! conn :file - {:data (blob/encode data)} - {:id file-id})))))) + + (when-let [data (some->> (seq unused) + (reduce ctkl/delete-component data) + (blob/encode))] + (db/update! conn :file + {:data data} + {:id file-id} + {::db/return-keys? false})) + + (count unused)))) + + +(def ^:private sql:get-changes + "SELECT id, data FROM file_change + WHERE file_id = ? AND data IS NOT NULL + ORDER BY created_at ASC") + +(def ^:private sql:mark-deleted-data-fragments + "UPDATE file_data_fragment + SET deleted_at = now() + WHERE file_id = ? + AND id != ALL(?::uuid[]) + RETURNING id") (defn- clean-data-fragments! [conn file-id data] - (letfn [(get-pointers-chunk [cursor] - (let [sql (str "select id, data, created_at " - " from file_change " - " where file_id = ? " - " and data is not null " - " and created_at < ? " - " order by created_at desc " - " limit 1;") - rows (db/exec! conn [sql file-id cursor])] - [(some-> rows peek :created-at) - (mapcat (comp feat.fdata/get-used-pointer-ids blob/decode :data) rows)]))] + (let [used (->> (db/cursor conn [sql:get-changes file-id]) + (into (feat.fdata/get-used-pointer-ids data) + (comp (map :data) + (map blob/decode) + (mapcat feat.fdata/get-used-pointer-ids)))) - (let [used (into (feat.fdata/get-used-pointer-ids data) - (d/iteration get-pointers-chunk - :vf second - :kf first - :initk (dt/now))) + unused (let [ids (db/create-array conn "uuid" used)] + (->> (db/exec! conn [sql:mark-deleted-data-fragments file-id ids]) + (into #{} (map :id))))] - sql (str "select id from file_data_fragment " - " where file_id = ? AND id != ALL(?::uuid[])") - used (db/create-array conn "uuid" used) - rows (db/exec! conn [sql file-id used])] + (doseq [id unused] + (l/trc :hint "mark deleted" + :rel "file-data-fragment" + :id (str id) + :file-id (str file-id))) - (doseq [fragment-id (map :id rows)] - (l/trc :hint "remove unused file data fragment" :id (str fragment-id)) - (db/delete! conn :file-data-fragment {:id fragment-id :file-id file-id}))))) + (count unused))) -(defn- process-file - [{:keys [::db/conn] :as cfg} {:keys [id data revn modified-at features] :as file}] - (l/dbg :hint "processing file" :file-id (str id) :modified-at modified-at) + +(defn- clean-file! + [{:keys [::db/conn] :as cfg} {:keys [id data revn modified-at] :as file}] (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id) pmap/*tracked* (pmap/create-tracked)] (let [data (-> (blob/decode data) (assoc :id id) - (pmg/migrate-data))] + (pmg/migrate-data)) - (clean-file-media! conn id data) - (clean-file-object-thumbnails! cfg id data) - (clean-file-thumbnails! cfg id revn) - (clean-deleted-components! conn id data) + nfm (clean-file-media! conn id data) + nfot (clean-file-object-thumbnails! cfg id data) + nft (clean-file-thumbnails! cfg id revn) + nc (clean-deleted-components! cfg id data) + ndf (clean-data-fragments! conn id data)] - (when (contains? features "fdata/pointer-map") - (clean-data-fragments! conn id data)) + (l/dbg :hint "file clened" + :file-id (str id) + :modified-at (dt/format-instant modified-at) + :media-objects nfm + :thumbnails nft + :object-thumbnails nfot + :components nc + :data-fragments ndf) ;; Mark file as trimmed (db/update! conn :file {:has-media-trimmed true} - {:id id}) + {:id id} + {::db/return-keys? false}) (feat.fdata/persist-pointers! cfg id)))) diff --git a/backend/src/app/tasks/objects_gc.clj b/backend/src/app/tasks/objects_gc.clj index 83b86dcdea..4dec5fa0d5 100644 --- a/backend/src/app/tasks/objects_gc.clj +++ b/backend/src/app/tasks/objects_gc.clj @@ -8,7 +8,6 @@ "A maintenance task that performs a general purpose garbage collection of deleted or unreachable objects." (:require - [app.common.data :as d] [app.common.logging :as l] [app.config :as cf] [app.db :as db] @@ -18,12 +17,15 @@ [clojure.spec.alpha :as s] [integrant.core :as ig])) -(declare ^:private delete-profiles!) -(declare ^:private delete-teams!) -(declare ^:private delete-fonts!) -(declare ^:private delete-projects!) +(declare ^:private delete-file-data-fragments!) +(declare ^:private delete-file-media-objects!) +(declare ^:private delete-file-object-thumbnails!) +(declare ^:private delete-file-thumbnails!) (declare ^:private delete-files!) -(declare ^:private delete-orphan-teams!) +(declare ^:private delete-fonts!) +(declare ^:private delete-profiles!) +(declare ^:private delete-projects!) +(declare ^:private delete-teams!) (defmethod ig/pre-init-spec ::handler [_] (s/keys :req [::db/pool ::sto/storage])) @@ -33,211 +35,320 @@ (assoc cfg ::min-age cf/deletion-delay)) (defmethod ig/init-key ::handler - [_ {:keys [::db/pool ::sto/storage] :as cfg}] + [_ cfg] (fn [params] - (db/with-atomic [conn pool] - (let [min-age (or (:min-age params) (::min-age cfg)) - _ (l/info :hint "gc started" - :min-age (dt/format-duration min-age) - :rollback? (boolean (:rollback? params))) + (db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}] + ;; Disable deletion protection for the current transaction + (db/exec-one! conn ["SET LOCAL rules.deletion_protection TO off"]) + (db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"]) - storage (media/configure-assets-storage storage conn) - cfg (-> cfg - (assoc ::min-age (db/interval min-age)) - (assoc ::conn conn) - (assoc ::storage storage)) + (let [min-age (dt/duration (or (:min-age params) (::min-age cfg))) + cfg (-> cfg + (assoc ::min-age (db/interval min-age)) + (update ::sto/storage media/configure-assets-storage conn)) - htotal (+ (delete-profiles! cfg) - (delete-teams! cfg) - (delete-projects! cfg) - (delete-files! cfg) - (delete-fonts! cfg)) - stotal (delete-orphan-teams! cfg)] + total (reduce + 0 + [(delete-profiles! cfg) + (delete-teams! cfg) + (delete-fonts! cfg) + (delete-projects! cfg) + (delete-files! cfg) + (delete-file-thumbnails! cfg) + (delete-file-object-thumbnails! cfg) + (delete-file-data-fragments! cfg) + (delete-file-media-objects! cfg)])] - (l/info :hint "gc finished" - :deleted htotal - :orphans stotal - :rollback? (boolean (:rollback? params))) + (l/info :hint "task finished" + :deleted total + :rollback? (boolean (:rollback? params))) - (when (:rollback? params) - (db/rollback! conn)) + (when (:rollback? params) + (db/rollback! conn)) - {:processed (+ stotal htotal) - :orphans stotal})))) + {:processed total}))))) -(def ^:private sql:get-profiles-chunk - "select id, photo_id, created_at from profile - where deleted_at is not null - and deleted_at < now() - ?::interval - and created_at < ? - order by created_at desc - limit 10 - for update skip locked") +(def ^:private sql:get-profiles + "SELECT id, photo_id FROM profile + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") (defn- delete-profiles! - [{:keys [::conn ::min-age ::storage] :as cfg}] - (letfn [(get-chunk [cursor] - (let [rows (db/exec! conn [sql:get-profiles-chunk min-age cursor])] - [(some->> rows peek :created-at) rows])) + [{:keys [::db/conn ::min-age ::sto/storage] :as cfg}] + (->> (db/cursor conn [sql:get-profiles min-age]) + (reduce (fn [total {:keys [id photo-id]}] + (l/trc :hint "permanently delete" :rel "profile" :id (str id)) - (process-profile [total {:keys [id photo-id]}] - (l/debug :hint "permanently delete profile" :id (str id)) + ;; Mark as deleted the storage object + (some->> photo-id (sto/touch-object! storage)) - ;; Mark as deleted the storage object related with the - ;; photo-id field. - (some->> photo-id (sto/touch-object! storage)) + ;; And finally, permanently delete the profile. The + ;; relevant objects will be deleted using DELETE + ;; CASCADE database triggers. This may leave orphan + ;; teams, but there is a special task for deleting + ;; orphaned teams. + (db/delete! conn :profile + {:id id} + {::db/return-keys? false}) - ;; And finally, permanently delete the profile. - (db/delete! conn :profile {:id id}) + (inc total)) + 0))) - (inc total))] - - (->> (d/iteration get-chunk :vf second :kf first :initk (dt/now)) - (reduce process-profile 0)))) - -(def ^:private sql:get-teams-chunk - "select id, photo_id, created_at from team - where deleted_at is not null - and deleted_at < now() - ?::interval - and created_at < ? - order by created_at desc - limit 10 - for update skip locked") +(def ^:private sql:get-teams + "SELECT deleted_at, id, photo_id FROM team + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") (defn- delete-teams! - [{:keys [::conn ::min-age ::storage] :as cfg}] - (letfn [(get-chunk [cursor] - (let [rows (db/exec! conn [sql:get-teams-chunk min-age cursor])] - [(some->> rows peek :created-at) rows])) + [{:keys [::db/conn ::min-age ::sto/storage] :as cfg}] - (process-team [total {:keys [id photo-id]}] - (l/debug :hint "permanently delete team" :id (str id)) + (->> (db/cursor conn [sql:get-teams min-age]) + (reduce (fn [total {:keys [id photo-id deleted-at]}] + (l/trc :hint "permanently delete" + :rel "team" + :id (str id) + :deleted-at (dt/format-instant deleted-at)) - ;; Mark as deleted the storage object related with the - ;; photo-id field. - (some->> photo-id (sto/touch-object! storage)) + ;; Mark as deleted the storage object + (some->> photo-id (sto/touch-object! storage)) - ;; And finally, permanently delete the team. - (db/delete! conn :team {:id id}) + ;; And finally, permanently delete the team. + (db/delete! conn :team + {:id id} + {::db/return-keys? false}) - (inc total))] + ;; Mark for deletion in cascade + (db/update! conn :team-font-variant + {:deleted-at deleted-at} + {:team-id id} + {::db/return-keys? false}) - (->> (d/iteration get-chunk :vf second :kf first :initk (dt/now)) - (reduce process-team 0)))) + (db/update! conn :project + {:deleted-at deleted-at} + {:team-id id} + {::db/return-keys? false}) -(def ^:private sql:get-orphan-teams-chunk - "select t.id, t.created_at - from team as t - left join team_profile_rel as tpr - on (t.id = tpr.team_id) - where tpr.profile_id is null - and t.created_at < ? - order by t.created_at desc - limit 10 - for update of t skip locked;") + (inc total)) + 0))) -(defn- delete-orphan-teams! - "Find all orphan teams (with no members and mark them for - deletion (soft delete)." - [{:keys [::conn] :as cfg}] - (letfn [(get-chunk [cursor] - (let [rows (db/exec! conn [sql:get-orphan-teams-chunk cursor])] - [(some->> rows peek :created-at) rows])) - - (process-team [total {:keys [id]}] - (let [result (db/update! conn :team - {:deleted-at (dt/now)} - {:id id :deleted-at nil} - {::db/return-keys? false}) - count (db/get-update-count result)] - (when (pos? count) - (l/debug :hint "mark team for deletion" :id (str id))) - - (+ total count)))] - - (->> (d/iteration get-chunk :vf second :kf first :initk (dt/now)) - (reduce process-team 0)))) - -(def ^:private sql:get-fonts-chunk - "select id, created_at, woff1_file_id, woff2_file_id, otf_file_id, ttf_file_id - from team_font_variant - where deleted_at is not null - and deleted_at < now() - ?::interval - and created_at < ? - order by created_at desc - limit 10 - for update skip locked") +(def ^:private sql:get-fonts + "SELECT id, team_id, deleted_at, woff1_file_id, woff2_file_id, otf_file_id, ttf_file_id + FROM team_font_variant + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") (defn- delete-fonts! - [{:keys [::conn ::min-age ::storage] :as cfg}] - (letfn [(get-chunk [cursor] - (let [rows (db/exec! conn [sql:get-fonts-chunk min-age cursor])] - [(some->> rows peek :created-at) rows])) + [{:keys [::db/conn ::min-age ::sto/storage] :as cfg}] + (->> (db/cursor conn [sql:get-fonts min-age]) + (reduce (fn [total {:keys [id team-id deleted-at] :as font}] + (l/trc :hint "permanently delete" + :rel "team-font-variant" + :id (str id) + :team-id (str team-id) + :deleted-at (dt/format-instant deleted-at)) - (process-font [total {:keys [id] :as font}] - (l/debug :hint "permanently delete font variant" :id (str id)) + ;; Mark as deleted the all related storage objects + (some->> (:woff1-file-id font) (sto/touch-object! storage)) + (some->> (:woff2-file-id font) (sto/touch-object! storage)) + (some->> (:otf-file-id font) (sto/touch-object! storage)) + (some->> (:ttf-file-id font) (sto/touch-object! storage)) - ;; Mark as deleted the all related storage objects - (some->> (:woff1-file-id font) (sto/touch-object! storage)) - (some->> (:woff2-file-id font) (sto/touch-object! storage)) - (some->> (:otf-file-id font) (sto/touch-object! storage)) - (some->> (:ttf-file-id font) (sto/touch-object! storage)) + ;; And finally, permanently delete the team font variant + (db/delete! conn :team-font-variant + {:id id} + {::db/return-keys? false}) - ;; And finally, permanently delete the team font variant - (db/delete! conn :team-font-variant {:id id}) + (inc total)) + 0))) - (inc total))] - - (->> (d/iteration get-chunk :vf second :kf first :initk (dt/now)) - (reduce process-font 0)))) - -(def ^:private sql:get-projects-chunk - "select id, created_at - from project - where deleted_at is not null - and deleted_at < now() - ?::interval - and created_at < ? - order by created_at desc - limit 10 - for update skip locked") +(def ^:private sql:get-projects + "SELECT id, deleted_at, team_id + FROM project + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") (defn- delete-projects! - [{:keys [::conn ::min-age] :as cfg}] - (letfn [(get-chunk [cursor] - (let [rows (db/exec! conn [sql:get-projects-chunk min-age cursor])] - [(some->> rows peek :created-at) rows])) + [{:keys [::db/conn ::min-age] :as cfg}] + (->> (db/cursor conn [sql:get-projects min-age]) + (reduce (fn [total {:keys [id team-id deleted-at]}] + (l/trc :hint "permanently delete" + :rel "project" + :id (str id) + :team-id (str team-id) + :deleted-at (dt/format-instant deleted-at)) + ;; And finally, permanently delete the project. + (db/delete! conn :project + {:id id} + {::db/return-keys? false}) - (process-project [total {:keys [id]}] - (l/debug :hint "permanently delete project" :id (str id)) - ;; And finally, permanently delete the project. - (db/delete! conn :project {:id id}) + ;; Mark files to be deleted + (db/update! conn :file + {:deleted-at deleted-at} + {:project-id id} + {::db/return-keys? false}) - (inc total))] + (inc total)) + 0))) - (->> (d/iteration get-chunk :vf second :kf first :initk (dt/now)) - (reduce process-project 0)))) - -(def ^:private sql:get-files-chunk - "select id, created_at - from file - where deleted_at is not null - and deleted_at < now() - ?::interval - and created_at < ? - order by created_at desc - limit 10 - for update skip locked") +(def ^:private sql:get-files + "SELECT id, deleted_at, project_id + FROM file + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") (defn- delete-files! - [{:keys [::conn ::min-age] :as cfg}] - (letfn [(get-chunk [cursor] - (let [rows (db/exec! conn [sql:get-files-chunk min-age cursor])] - [(some->> rows peek :created-at) rows])) + [{:keys [::db/conn ::min-age] :as cfg}] + (->> (db/cursor conn [sql:get-files min-age]) + (reduce (fn [total {:keys [id deleted-at project-id]}] + (l/trc :hint "permanently delete" + :rel "file" + :id (str id) + :project-id (str project-id) + :deleted-at (dt/format-instant deleted-at)) - (process-file [total {:keys [id]}] - (l/debug :hint "permanently delete file" :id (str id)) - ;; And finally, permanently delete the file. - (db/delete! conn :file {:id id}) - (inc total))] + ;; And finally, permanently delete the file. + (db/delete! conn :file + {:id id} + {::db/return-keys? false}) - (->> (d/iteration get-chunk :vf second :kf first :initk (dt/now)) - (reduce process-file 0)))) + ;; Mark file media objects to be deleted + (db/update! conn :file-media-object + {:deleted-at deleted-at} + {:file-id id} + {::db/return-keys? false}) + + ;; Mark thumbnails to be deleted + (db/update! conn :file-thumbnail + {:deleted-at deleted-at} + {:file-id id} + {::db/return-keys? false}) + (db/update! conn :file-tagged-object-thumbnail + {:deleted-at deleted-at} + {:file-id id} + {::db/return-keys? false}) + + (inc total)) + 0))) + + +(def ^:private sql:get-file-thumbnails + "SELECT file_id, revn, media_id, deleted_at + FROM file_thumbnail + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") + +(defn delete-file-thumbnails! + [{:keys [::db/conn ::min-age ::sto/storage] :as cfg}] + (->> (db/cursor conn [sql:get-file-thumbnails min-age]) + (reduce (fn [total {:keys [file-id revn media-id deleted-at]}] + (l/trc :hint "permanently delete" + :rel "file-thumbnail" + :file-id (str file-id) + :revn revn + :deleted-at (dt/format-instant deleted-at)) + + ;; Mark as deleted the storage object + (some->> media-id (sto/touch-object! storage)) + + ;; And finally, permanently delete the object + (db/delete! conn :file-thumbnail {:file-id file-id :revn revn}) + + (inc total)) + 0))) + +(def ^:private sql:get-file-object-thumbnails + "SELECT file_id, object_id, media_id, deleted_at + FROM file_tagged_object_thumbnail + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") + +(defn delete-file-object-thumbnails! + [{:keys [::db/conn ::min-age ::sto/storage] :as cfg}] + (->> (db/cursor conn [sql:get-file-object-thumbnails min-age]) + (reduce (fn [total {:keys [file-id object-id media-id deleted-at]}] + (l/trc :hint "permanently delete" + :rel "file-tagged-object-thumbnail" + :file-id (str file-id) + :object-id object-id + :deleted-at (dt/format-instant deleted-at)) + + ;; Mark as deleted the storage object + (some->> media-id (sto/touch-object! storage)) + + ;; And finally, permanently delete the object + (db/delete! conn :file-tagged-object-thumbnail {:file-id file-id :object-id object-id}) + + (inc total)) + 0))) + +(def ^:private sql:get-file-data-fragments + "SELECT file_id, id, deleted_at + FROM file_data_fragment + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") + +(defn- delete-file-data-fragments! + [{:keys [::db/conn ::min-age] :as cfg}] + (->> (db/cursor conn [sql:get-file-data-fragments min-age]) + (reduce (fn [total {:keys [file-id id deleted-at]}] + (l/trc :hint "permanently delete" + :rel "file-data-fragment" + :id (str id) + :file-id (str file-id) + :deleted-at (dt/format-instant deleted-at)) + + (db/delete! conn :file-data-fragment {:file-id file-id :id id}) + + (inc total)) + 0))) + +(def ^:private sql:get-file-media-objects + "SELECT id, file_id, media_id, thumbnail_id, deleted_at + FROM file_media_object + WHERE deleted_at IS NOT NULL + AND deleted_at < now() - ?::interval + ORDER BY deleted_at ASC + FOR UPDATE + SKIP LOCKED") + +(defn- delete-file-media-objects! + [{:keys [::db/conn ::min-age ::sto/storage] :as cfg}] + (->> (db/cursor conn [sql:get-file-media-objects min-age]) + (reduce (fn [total {:keys [id file-id deleted-at] :as fmo}] + (l/trc :hint "permanently delete" + :rel "file-media-object" + :id (str id) + :file-id (str file-id) + :deleted-at (dt/format-instant deleted-at)) + + ;; Mark as deleted the all related storage objects + (some->> (:media-id fmo) (sto/touch-object! storage)) + (some->> (:thumbnail-id fmo) (sto/touch-object! storage)) + + (db/delete! conn :file-media-object {:id id}) + + (inc total)) + 0))) diff --git a/backend/src/app/tasks/orphan_teams_gc.clj b/backend/src/app/tasks/orphan_teams_gc.clj new file mode 100644 index 0000000000..f7f1daedf5 --- /dev/null +++ b/backend/src/app/tasks/orphan_teams_gc.clj @@ -0,0 +1,60 @@ +;; 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.tasks.orphan-teams-gc + "A maintenance task that performs orphan teams GC." + (:require + [app.common.logging :as l] + [app.db :as db] + [app.util.time :as dt] + [clojure.spec.alpha :as s] + [integrant.core :as ig])) + +(declare ^:private delete-orphan-teams!) + +(defmethod ig/pre-init-spec ::handler [_] + (s/keys :req [::db/pool])) + +(defmethod ig/init-key ::handler + [_ cfg] + (fn [params] + (db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}] + (l/inf :hint "gc started" :rollback? (boolean (:rollback? params))) + (let [total (delete-orphan-teams! cfg)] + (l/inf :hint "task finished" + :teams total + :rollback? (boolean (:rollback? params))) + + (when (:rollback? params) + (db/rollback! conn)) + + {:processed total}))))) + +(def ^:private sql:get-orphan-teams + "SELECT t.id + FROM team AS t + LEFT JOIN team_profile_rel AS tpr + ON (t.id = tpr.team_id) + WHERE tpr.profile_id IS NULL + AND t.deleted_at IS NULL + ORDER BY t.created_at ASC + FOR UPDATE OF t + SKIP LOCKED") + +(defn- delete-orphan-teams! + "Find all orphan teams (with no members) and mark them for + deletion (soft delete)." + [{:keys [::db/conn] :as cfg}] + (->> (db/cursor conn sql:get-orphan-teams) + (map :id) + (reduce (fn [total team-id] + (l/trc :hint "mark orphan team for deletion" :id (str team-id)) + (db/update! conn :team + {:deleted-at (dt/now)} + {:id team-id} + {::db/return-keys? false}) + (inc total)) + 0))) diff --git a/backend/test/backend_tests/helpers.clj b/backend/test/backend_tests/helpers.clj index 3fad161142..646905c515 100644 --- a/backend/test/backend_tests/helpers.clj +++ b/backend/test/backend_tests/helpers.clj @@ -175,12 +175,11 @@ " WHERE table_schema = 'public' " " AND table_name != 'migrations';")] (db/with-atomic [conn *pool*] + (db/exec-one! conn ["SET CONSTRAINTS ALL DEFERRED"]) + (db/exec-one! conn ["SET LOCAL rules.deletion_protection TO off"]) (let [result (->> (db/exec! conn [sql]) (map :table-name) - (remove #(= "task" %))) - sql (str "TRUNCATE " - (apply str (interpose ", " result)) - " CASCADE;")] + (remove #(= "task" %)))] (doseq [table result] (db/exec! conn [(str "delete from " table ";")])))) @@ -433,11 +432,11 @@ (us/pretty-explain data)) (= :params-validation (:code data)) - (app.common.pprint/pprint + (println (sm/humanize-explain (::sm/explain data))) (= :data-validation (:code data)) - (app.common.pprint/pprint + (println (sm/humanize-explain (::sm/explain data))) (= :service-error (:type data)) @@ -512,6 +511,10 @@ [sql] (db/exec! *pool* sql)) +(defn db-exec-one! + [sql] + (db/exec-one! *pool* sql)) + (defn db-delete! [& params] (apply db/delete! *pool* params)) diff --git a/backend/test/backend_tests/rpc_file_test.clj b/backend/test/backend_tests/rpc_file_test.clj index cbf96c2167..cbce720c56 100644 --- a/backend/test/backend_tests/rpc_file_test.clj +++ b/backend/test/backend_tests/rpc_file_test.clj @@ -149,7 +149,7 @@ shape-id (uuid/random)] ;; Preventive file-gc - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; Check the number of fragments before adding the page @@ -175,7 +175,7 @@ (t/is (= 2 (count rows)))) ;; The file-gc should remove unused fragments - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) @@ -203,7 +203,7 @@ (t/is (= 3 (count rows)))) ;; The file-gc should remove unused fragments - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; Check the number of fragments; should be 3 because changes @@ -220,12 +220,23 @@ ;; The file-gc should remove fragments related to changes ;; snapshots previously deleted. - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; Check the number of fragments; (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] - (t/is (= 2 (count rows))))))) + ;; (pp/pprint rows) + (t/is (= 3 (count rows))) + (t/is (= 2 (count (remove (comp some? :deleted-at) rows))))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) + + (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] + (t/is (= 2 (count rows)))) + ))) + + (t/deftest file-gc-task-with-thumbnails (letfn [(add-file-media-object [& {:keys [profile-id file-id]}] @@ -301,17 +312,16 @@ ;; freeze because of the deduplication (we have uploaded 2 times ;; the same files). - (let [task (:app.storage/gc-touched-task th/*system*) - res (task {:min-age (dt/duration 0)})] + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] (t/is (= 2 (:freeze res))) (t/is (= 0 (:delete res)))) ;; run the file-gc task immediately without forced min-age - (let [res (th/run-task! "file-gc")] + (let [res (th/run-task! :file-gc)] (t/is (= 0 (:processed res)))) ;; run the task again - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; retrieve file and check trimmed attribute @@ -319,8 +329,17 @@ (t/is (true? (:has-media-trimmed row)))) ;; check file media objects - (let [rows (th/db-exec! ["select * from file_media_object where file_id = ?" (:id file)])] - (t/is (= 1 (count rows)))) + (let [rows (th/db-query :file-media-object {:file-id (:id file)})] + (t/is (= 2 (count rows))) + (t/is (= 1 (count (remove (comp some? :deleted-at) rows))))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 2 (:processed res)))) + + ;; check file media objects + (let [rows (th/db-query :file-media-object {:file-id (:id file)})] + (t/is (= 1 (count rows))) + (t/is (= 1 (count (remove (comp some? :deleted-at) rows))))) ;; The underlying storage objects are still available. (t/is (some? (sto/get-object storage (:media-id fmo2)))) @@ -340,15 +359,16 @@ ;; Now, we have deleted the usage of pointers to the ;; file-media-objects, if we paste file-gc, they should be marked ;; as deleted. - (let [task (:app.tasks.file-gc/handler th/*system*) - res (task {:min-age (dt/duration 0)})] + (let [res (th/run-task! :file-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; Now that file-gc have deleted the file-media-object usage, ;; lets execute the touched-gc task, we should see that two of ;; them are marked to be deleted. - (let [task (:app.storage/gc-touched-task th/*system*) - res (task {:min-age (dt/duration 0)})] + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] (t/is (= 0 (:freeze res))) (t/is (= 2 (:delete res)))) @@ -457,11 +477,14 @@ :strokes [{:opacity 1 :stroke-image {:id (:id fmo5) :width 100 :height 100 :mtype "image/jpeg"}}]})}]) ;; run the file-gc task immediately without forced min-age - (let [res (th/run-task! "file-gc")] + (let [res (th/run-task! :file-gc)] (t/is (= 0 (:processed res)))) ;; run the task again - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; retrieve file and check trimmed attribute @@ -494,15 +517,16 @@ ;; Now, we have deleted the usage of pointers to the ;; file-media-objects, if we paste file-gc, they should be marked ;; as deleted. - (let [task (:app.tasks.file-gc/handler th/*system*) - res (task {:min-age (dt/duration 0)})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 5 (:processed res)))) + ;; Now that file-gc have deleted the file-media-object usage, ;; lets execute the touched-gc task, we should see that two of ;; them are marked to be deleted. - (let [task (:app.storage/gc-touched-task th/*system*) - res (task {:min-age (dt/duration 0)})] + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] (t/is (= 0 (:freeze res))) (t/is (= 2 (:delete res)))) @@ -515,7 +539,6 @@ (t/is (nil? (sto/get-object storage (:media-id fmo2)))) (t/is (nil? (sto/get-object storage (:media-id fmo1))))))) - (t/deftest file-gc-task-with-object-thumbnails (letfn [(insert-file-object-thumbnail! [& {:keys [profile-id file-id page-id frame-id]}] (let [object-id (thc/fmt-object-id file-id page-id frame-id "frame") @@ -609,16 +632,16 @@ ;; because of the deduplication (we have uploaded 2 times the ;; same files). - (let [res (th/run-task! "storage-gc-touched" {:min-age (dt/duration 0)})] + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] (t/is (= 1 (:freeze res))) (t/is (= 0 (:delete res)))) ;; run the file-gc task immediately without forced min-age - (let [res (th/run-task! "file-gc")] + (let [res (th/run-task! :file-gc)] (t/is (= 0 (:processed res)))) ;; run the task again - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; retrieve file and check trimmed attribute @@ -648,22 +671,29 @@ :page-id page-id :id frame-id-2}]) - (let [res (th/run-task! "file-gc" {:min-age (dt/duration 0)})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) - (let [rows (th/db-exec! ["select * from file_tagged_object_thumbnail where file_id = ?" file-id])] - ;; (pp/pprint rows) - (t/is (= 1 (count rows))) + (let [rows (th/db-query :file-tagged-object-thumbnail {:file-id file-id})] + (t/is (= 2 (count rows))) + (t/is (= 1 (count (remove (comp some? :deleted-at) rows)))) + (t/is (= (thc/fmt-object-id file-id page-id frame-id-1 "frame") (-> rows first :object-id)))) - ;; Now that file-gc have deleted the object thumbnail lets + ;; Now that file-gc have marked for deletion the object + ;; thumbnail lets execute the objects-gc task which remove + ;; the rows and mark as touched the storage object rows + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 2 (:processed res)))) + + ;; Now that objects-gc have deleted the object thumbnail lets ;; execute the touched-gc task - (let [res (th/run-task! "storage-gc-touched" {:min-age (dt/duration 0)})] + (let [res (th/run-task! "storage-gc-touched" {:min-age 0})] (t/is (= 1 (:freeze res)))) ;; check file media objects - (let [rows (th/db-exec! ["select * from storage_object where deleted_at is null"])] + (let [rows (th/db-query :storage-object {:deleted-at nil})] ;; (pp/pprint rows) (t/is (= 1 (count rows)))) @@ -676,31 +706,32 @@ :page-id page-id :id frame-id-1}]) - (let [res (th/run-task! "file-gc" {:min-age (dt/duration 0)})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) - (let [rows (th/db-exec! ["select * from file_tagged_object_thumbnail where file_id = ?" file-id])] - (t/is (= 0 (count rows)))) + (let [rows (th/db-query :file-tagged-object-thumbnail {:file-id file-id})] + (t/is (= 1 (count rows))) + (t/is (= 0 (count (remove (comp some? :deleted-at) rows))))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] + ;; (pp/pprint res) + (t/is (= 1 (:processed res)))) ;; We still have th storage objects in the table - (let [rows (th/db-exec! ["select * from storage_object where deleted_at is null"])] + (let [rows (th/db-query :storage-object {:deleted-at nil})] ;; (pp/pprint rows) (t/is (= 1 (count rows)))) ;; Now that file-gc have deleted the object thumbnail lets ;; execute the touched-gc task - (let [res (th/run-task! "storage-gc-touched" {:min-age (dt/duration 0)})] + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] (t/is (= 1 (:delete res)))) ;; check file media objects - (let [rows (th/db-exec! ["select * from storage_object where deleted_at is null"])] + (let [rows (th/db-query :storage-object {:deleted-at nil})] ;; (pp/pprint rows) (t/is (= 0 (count rows))))))) - - - - (t/deftest permissions-checks-creating-file (let [profile1 (th/create-profile* 1) profile2 (th/create-profile* 2) @@ -811,13 +842,12 @@ (t/is (th/ex-of-type? error :not-found)))) (t/deftest deletion - (let [task (:app.tasks.objects-gc/handler th/*system*) - profile1 (th/create-profile* 1) + (let [profile1 (th/create-profile* 1) file (th/create-file* 1 {:project-id (:default-project-id profile1) :profile-id (:id profile1)})] ;; file is not deleted because it does not meet all ;; conditions to be deleted. - (let [result (task {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age 0})] (t/is (= 0 (:processed result)))) ;; query the list of files @@ -848,7 +878,7 @@ (t/is (= 0 (count result))))) ;; run permanent deletion (should be noop) - (let [result (task {:min-age (dt/duration {:minutes 1})})] + (let [result (th/run-task! :objects-gc {:min-age (dt/duration {:minutes 1})})] (t/is (= 0 (:processed result)))) ;; query the list of file libraries of a after hard deletion @@ -862,7 +892,7 @@ (t/is (= 0 (count result))))) ;; run permanent deletion - (let [result (task {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age 0})] (t/is (= 1 (:processed result)))) ;; query the list of file libraries of a after hard deletion @@ -874,7 +904,8 @@ (let [error (:error out) error-data (ex-data error)] (t/is (th/ex-info? error)) - (t/is (= (:type error-data) :not-found)))))) + (t/is (= (:type error-data) :not-found)))) + )) (t/deftest object-thumbnails-ops @@ -1075,7 +1106,7 @@ (th/sleep 300) ;; run the task - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; check that object thumbnails are still here @@ -1104,13 +1135,19 @@ (t/is (= 2 (count res)))) ;; run the task again - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [res (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed res)))) ;; check that the unknown frame thumbnail is deleted - (let [res (th/db-exec! ["select * from file_tagged_object_thumbnail"])] - (t/is (= 1 (count res))))))) + (let [rows (th/db-query :file-tagged-object-thumbnail {:file-id (:id file)})] + (t/is (= 2 (count rows))) + (t/is (= 1 (count (remove (comp some? :deleted-at) rows))))) + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 2 (:processed res)))) + + (let [rows (th/db-query :file-tagged-object-thumbnail {:file-id (:id file)})] + (t/is (= 1 (count rows))))))) (t/deftest file-thumbnail-ops (let [prof (th/create-profile* 1 {:is-active true}) @@ -1155,12 +1192,19 @@ (t/testing "gc task" ;; make the file eligible for GC waiting 300ms (configured ;; timeout for testing) - (th/sleep 300) + (let [res (th/run-task! :file-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) - (let [res (th/run-task! "file-gc" {:min-age 0})] + (let [rows (th/db-query :file-thumbnail {:file-id (:id file)})] + (t/is (= 2 (count rows))) + (t/is (= 1 (count (remove (comp some? :deleted-at) rows))))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] (t/is (= 1 (:processed res)))) (let [rows (th/db-query :file-thumbnail {:file-id (:id file)})] (t/is (= 1 (count rows))))))) + + diff --git a/backend/test/backend_tests/rpc_file_thumbnails_test.clj b/backend/test/backend_tests/rpc_file_thumbnails_test.clj index b31e955569..d88b5ed9f6 100644 --- a/backend/test/backend_tests/rpc_file_thumbnails_test.clj +++ b/backend/test/backend_tests/rpc_file_thumbnails_test.clj @@ -6,6 +6,7 @@ (ns backend-tests.rpc-file-thumbnails-test (:require + [app.common.pprint :as pp] [app.common.thumbnails :as thc] [app.common.types.shape :as cts] [app.common.uuid :as uuid] @@ -114,9 +115,12 @@ ;; Run the File GC task that should remove unused file object ;; thumbnails - (let [result (th/run-task! :file-gc {:min-age (dt/duration 0)})] + (let [result (th/run-task! :file-gc {:min-age 0})] (t/is (= 1 (:processed result)))) + (let [result (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 2 (:processed result)))) + ;; check if row2 related thumbnail row still exists (let [[row :as rows] (th/db-query :file-tagged-object-thumbnail {:file-id (:id file)} @@ -141,7 +145,7 @@ ;; Run the storage gc deleted task, it should permanently delete ;; all storage objects related to the deleted thumbnails - (let [result (th/run-task! :storage-gc-deleted {:min-age (dt/duration 0)})] + (let [result (th/run-task! :storage-gc-deleted {:min-age 0})] (t/is (= 1 (:deleted result)))) (t/is (nil? (sto/get-object storage (:media-id row1)))) @@ -188,13 +192,12 @@ (let [[row1 row2 :as rows] (th/db-query :file-thumbnail {:file-id (:id file)} - {:order-by [[:created-at :asc]]})] + {:order-by [[:revn :asc]]})] (t/is (= 2 (count rows))) (t/is (= (:file-id data1) (:file-id row1))) (t/is (= (:revn data1) (:revn row1))) (t/is (uuid? (:media-id row1))) - (t/is (= (:file-id data2) (:file-id row2))) (t/is (= (:revn data2) (:revn row2))) (t/is (uuid? (:media-id row2))) @@ -215,7 +218,10 @@ ;; Run the File GC task that should remove unused file object ;; thumbnails - (let [result (th/run-task! :file-gc {:min-age (dt/duration 0)})] + (let [result (th/run-task! :file-gc {:min-age 0})] + (t/is (= 1 (:processed result)))) + + (let [result (th/run-task! :objects-gc {:min-age 0})] (t/is (= 1 (:processed result)))) ;; check if row1 related thumbnail row still exists @@ -227,6 +233,9 @@ (t/is (= (:object-id data1) (:object-id row))) (t/is (uuid? (:media-id row1)))) + (let [result (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 1 (:delete result)))) + ;; Check if storage objects still exists after file-gc (t/is (nil? (sto/get-object storage (:media-id row1)))) (t/is (some? (sto/get-object storage (:media-id row2)))) @@ -236,10 +245,42 @@ ;; Run the storage gc deleted task, it should permanently delete ;; all storage objects related to the deleted thumbnails - (let [result (th/run-task! :storage-gc-deleted {:min-age (dt/duration 0)})] + (let [result (th/run-task! :storage-gc-deleted {:min-age 0})] (t/is (= 1 (:deleted result)))) - (t/is (some? (sto/get-object storage (:media-id row2))))))) + (t/is (some? (sto/get-object storage (:media-id row2)))) + + ))) + +(t/deftest error-on-direct-storage-obj-deletion + (let [storage (::sto/storage th/*system*) + profile (th/create-profile* 1) + file (th/create-file* 1 {:profile-id (:id profile) + :project-id (:default-project-id profile) + :is-shared false + :revn 3}) + + data1 {::th/type :create-file-thumbnail + ::rpc/profile-id (:id profile) + :file-id (:id file) + :revn 2 + :media {:filename "sample.jpg" + :size 7923 + :path (th/tempfile "backend_tests/test_files/sample2.jpg") + :mtype "image/jpeg"}}] + + (let [out (th/command! data1)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (contains? (:result out) :uri))) + + (let [[row1 :as rows] (th/db-query :file-thumbnail {:file-id (:id file)})] + (t/is (= 1 (count rows))) + + (t/is (thrown? org.postgresql.util.PSQLException + (th/db-delete! :storage-object {:id (:media-id row1)})))))) + + (t/deftest get-file-object-thumbnail (let [storage (::sto/storage th/*system*) diff --git a/backend/test/backend_tests/rpc_font_test.clj b/backend/test/backend_tests/rpc_font_test.clj index d1c3bdd60a..5d31f14b1f 100644 --- a/backend/test/backend_tests/rpc_font_test.clj +++ b/backend/test/backend_tests/rpc_font_test.clj @@ -92,3 +92,192 @@ :font-family :font-weight :font-style)))) + +(t/deftest font-deletion-1 + (let [prof (th/create-profile* 1 {:is-active true}) + team-id (:default-team-id prof) + proj-id (:default-project-id prof) + font-id (uuid/custom 10 1) + + data1 (-> (io/resource "backend_tests/test_files/font-1.woff") + io/input-stream + io/read-as-bytes) + + data2 (-> (io/resource "backend_tests/test_files/font-2.woff") + io/input-stream + io/read-as-bytes)] + + ;; Create front variant + (let [params {::th/type :create-font-variant + ::rpc/profile-id (:id prof) + :team-id team-id + :font-id font-id + :font-family "somefont" + :font-weight 400 + :font-style "normal" + :data {"font/woff" data1}} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out)))) + + (let [params {::th/type :create-font-variant + ::rpc/profile-id (:id prof) + :team-id team-id + :font-id font-id + :font-family "somefont" + :font-weight 500 + :font-style "normal" + :data {"font/woff" data2}} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 6 (:freeze res)))) + + (let [params {::th/type :delete-font + ::rpc/profile-id (:id prof) + :team-id team-id + :id font-id} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (nil? (:result out)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 6 (:freeze res))) + (t/is (= 0 (:delete res)))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 2 (:processed res)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 0 (:freeze res))) + (t/is (= 6 (:delete res)))) + )) + +(t/deftest font-deletion-2 + (let [prof (th/create-profile* 1 {:is-active true}) + team-id (:default-team-id prof) + proj-id (:default-project-id prof) + font-id (uuid/custom 10 1) + + data1 (-> (io/resource "backend_tests/test_files/font-1.woff") + io/input-stream + io/read-as-bytes) + + data2 (-> (io/resource "backend_tests/test_files/font-2.woff") + io/input-stream + io/read-as-bytes)] + + ;; Create front variant + (let [params {::th/type :create-font-variant + ::rpc/profile-id (:id prof) + :team-id team-id + :font-id font-id + :font-family "somefont" + :font-weight 400 + :font-style "normal" + :data {"font/woff" data1}} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out)))) + + (let [params {::th/type :create-font-variant + ::rpc/profile-id (:id prof) + :team-id team-id + :font-id (uuid/custom 10 2) + :font-family "somefont" + :font-weight 400 + :font-style "normal" + :data {"font/woff" data2}} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 6 (:freeze res)))) + + (let [params {::th/type :delete-font + ::rpc/profile-id (:id prof) + :team-id team-id + :id font-id} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (nil? (:result out)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 3 (:freeze res))) + (t/is (= 0 (:delete res)))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 0 (:freeze res))) + (t/is (= 3 (:delete res)))) + )) + +(t/deftest font-deletion-3 + (let [prof (th/create-profile* 1 {:is-active true}) + team-id (:default-team-id prof) + proj-id (:default-project-id prof) + font-id (uuid/custom 10 1) + + data1 (-> (io/resource "backend_tests/test_files/font-1.woff") + io/input-stream + io/read-as-bytes) + + data2 (-> (io/resource "backend_tests/test_files/font-2.woff") + io/input-stream + io/read-as-bytes) + params1 {::th/type :create-font-variant + ::rpc/profile-id (:id prof) + :team-id team-id + :font-id font-id + :font-family "somefont" + :font-weight 400 + :font-style "normal" + :data {"font/woff" data1}} + + params2 {::th/type :create-font-variant + ::rpc/profile-id (:id prof) + :team-id team-id + :font-id font-id + :font-family "somefont" + :font-weight 500 + :font-style "normal" + :data {"font/woff" data2}} + + out1 (th/command! params1) + out2 (th/command! params2)] + + ;; (th/print-result! out1) + (t/is (nil? (:error out1))) + (t/is (nil? (:error out2))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 6 (:freeze res)))) + + (let [params {::th/type :delete-font-variant + ::rpc/profile-id (:id prof) + :team-id team-id + :id (-> out1 :result :id)} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (nil? (:result out)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 3 (:freeze res))) + (t/is (= 0 (:delete res)))) + + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) + + (let [res (th/run-task! :storage-gc-touched {:min-age 0})] + (t/is (= 0 (:freeze res))) + (t/is (= 3 (:delete res)))) + + )) diff --git a/backend/test/backend_tests/rpc_profile_test.clj b/backend/test/backend_tests/rpc_profile_test.clj index 64ccde95a3..0bfc01fc76 100644 --- a/backend/test/backend_tests/rpc_profile_test.clj +++ b/backend/test/backend_tests/rpc_profile_test.clj @@ -125,7 +125,7 @@ ;; profile is not deleted because it does not meet all ;; conditions to be deleted. - (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age 0})] (t/is (= 0 (:processed result)))) ;; Request profile to be deleted @@ -144,8 +144,16 @@ (t/is (= 1 (count (:result out))))) ;; execute permanent deletion task - (let [result (th/run-task! :objects-gc {:min-age (dt/duration "-1m")})] - (t/is (= 2 (:processed result)))) + (let [result (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 1 (:processed result)))) + + (let [row (th/db-get :team + {:id (:default-team-id prof)} + {::db/remove-deleted? false})] + (t/is (nil? (:deleted-at row)))) + + (let [result (th/run-task! :orphan-teams-gc {:min-age 0})] + (t/is (= 1 (:processed result)))) (let [row (th/db-get :team {:id (:default-team-id prof)} @@ -158,67 +166,9 @@ out (th/command! params)] ;; (th/print-result! out) (let [result (:result out)] - (t/is (= uuid/zero (:id result))))))) + (t/is (= uuid/zero (:id result))))) -(t/deftest profile-immediate-deletion - (let [prof1 (th/create-profile* 1) - prof2 (th/create-profile* 2) - file (th/create-file* 1 {:profile-id (:id prof1) - :project-id (:default-project-id prof1) - :is-shared false}) - - team (th/create-team* 1 {:profile-id (:id prof1)}) - _ (th/create-team-role* {:team-id (:id team) - :profile-id (:id prof2) - :role :admin})] - - ;; profile is not deleted because it does not meet all - ;; conditions to be deleted. - (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] - (t/is (= 0 (:orphans result))) - (t/is (= 0 (:processed result)))) - - ;; just delete the profile - (th/db-delete! :profile {:id (:id prof1)}) - - ;; query files after profile deletion, expecting not found - (let [params {::th/type :get-project-files - ::rpc/profile-id (:id prof1) - :project-id (:default-project-id prof1)} - out (th/command! params)] - ;; (th/print-result! out) - (t/is (not (th/success? out))) - (let [edata (-> out :error ex-data)] - (t/is (= :not-found (:type edata))))) - - ;; the files and projects still exists on the database - (let [files (th/db-query :file {:project-id (:default-project-id prof1)}) - projects (th/db-query :project {:team-id (:default-team-id prof1)})] - (t/is (= 1 (count files))) - (t/is (= 1 (count projects)))) - - ;; execute the gc task - (let [result (th/run-task! :objects-gc {:min-age (dt/duration "-1m")})] - (t/is (= 1 (:processed result))) - (t/is (= 1 (:orphans result)))) - - ;; Check the deletion flag on the default profile team - (let [row (th/db-get :team - {:id (:default-team-id prof1)} - {::db/remove-deleted? false})] - (t/is (dt/instant? (:deleted-at row)))) - - ;; Check the deletion flag on the shared team - (let [row (th/db-get :team - {:id (:id team)} - {::db/remove-deleted? false})] - (t/is (nil? (:deleted-at row)))) - - ;; Check the roles on the shared team - (let [rows (th/db-query :team-profile-rel {:team-id (:id team)})] - (t/is (= 1 (count rows))) - (t/is (= (:id prof2) (get-in rows [0 :profile-id]))) - (t/is (= false (get-in rows [0 :is-owner])))))) + )) (t/deftest registration-domain-whitelist (let [whitelist #{"gmail.com" "hey.com" "ya.ru"}] diff --git a/backend/test/backend_tests/rpc_project_test.clj b/backend/test/backend_tests/rpc_project_test.clj index acfb6fdf21..f35105a97f 100644 --- a/backend/test/backend_tests/rpc_project_test.clj +++ b/backend/test/backend_tests/rpc_project_test.clj @@ -172,14 +172,13 @@ (t/deftest test-deletion - (let [task (:app.tasks.objects-gc/handler th/*system*) - profile1 (th/create-profile* 1) + (let [profile1 (th/create-profile* 1) project (th/create-project* 1 {:team-id (:default-team-id profile1) :profile-id (:id profile1)})] ;; project is not deleted because it does not meet all ;; conditions to be deleted. - (let [result (task {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age 0})] (t/is (= 0 (:processed result)))) ;; query the list of projects @@ -187,6 +186,7 @@ ::rpc/profile-id (:id profile1) :team-id (:default-team-id profile1)} out (th/command! data)] + ;; (th/print-result! out) (t/is (nil? (:error out))) (let [result (:result out)] @@ -210,7 +210,7 @@ (t/is (= 1 (count result))))) ;; run permanent deletion (should be noop) - (let [result (task {:min-age (dt/duration {:minutes 1})})] + (let [result (th/run-task! :objects-gc {:min-age (dt/duration {:minutes 1})})] (t/is (= 0 (:processed result)))) ;; query the list of files of a after soft deletion @@ -224,7 +224,7 @@ (t/is (= 0 (count result))))) ;; run permanent deletion - (let [result (task {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age 0})] (t/is (= 1 (:processed result)))) ;; query the list of files of a after hard deletion diff --git a/backend/test/backend_tests/rpc_team_test.clj b/backend/test/backend_tests/rpc_team_test.clj index 45e4c48071..8252e9aa30 100644 --- a/backend/test/backend_tests/rpc_team_test.clj +++ b/backend/test/backend_tests/rpc_team_test.clj @@ -269,76 +269,6 @@ (t/is (= 1 (count members))) (t/is (true? (-> members first :can-edit)))))))) -(t/deftest team-deletion - (let [profile1 (th/create-profile* 1 {:is-active true}) - team (th/create-team* 1 {:profile-id (:id profile1)}) - pool (:app.db/pool th/*system*) - data {::th/type :delete-team - ::rpc/profile-id (:id profile1) - :team-id (:id team)}] - - ;; team is not deleted because it does not meet all - ;; conditions to be deleted. - (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] - (t/is (= 0 (:processed result)))) - - ;; query the list of teams - (let [data {::th/type :get-teams - ::rpc/profile-id (:id profile1)} - out (th/command! data)] - ;; (th/print-result! out) - (t/is (th/success? out)) - (let [result (:result out)] - (t/is (= 2 (count result))) - (t/is (= (:id team) (get-in result [1 :id]))) - (t/is (= (:default-team-id profile1) (get-in result [0 :id]))))) - - ;; Request team to be deleted - (let [params {::th/type :delete-team - ::rpc/profile-id (:id profile1) - :id (:id team)} - out (th/command! params)] - (t/is (th/success? out))) - - ;; query the list of teams after soft deletion - (let [data {::th/type :get-teams - ::rpc/profile-id (:id profile1)} - out (th/command! data)] - ;; (th/print-result! out) - (t/is (th/success? out)) - (let [result (:result out)] - (t/is (= 1 (count result))) - (t/is (= (:default-team-id profile1) (get-in result [0 :id]))))) - - ;; run permanent deletion (should be noop) - (let [result (th/run-task! :objects-gc {:min-age (dt/duration {:minutes 1})})] - (t/is (= 0 (:processed result)))) - - ;; query the list of projects after hard deletion - (let [data {::th/type :get-projects - ::rpc/profile-id (:id profile1) - :team-id (:id team)} - out (th/command! data)] - ;; (th/print-result! out) - (t/is (not (th/success? out))) - (let [edata (-> out :error ex-data)] - (t/is (= :not-found (:type edata))))) - - ;; run permanent deletion - (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] - (t/is (= 1 (:processed result)))) - - ;; query the list of projects of a after hard deletion - (let [data {::th/type :get-projects - ::rpc/profile-id (:id profile1) - :team-id (:id team)} - out (th/command! data)] - ;; (th/print-result! out) - - (t/is (not (th/success? out))) - (let [edata (-> out :error ex-data)] - (t/is (= :not-found (:type edata))))))) - (t/deftest query-team-invitations (let [prof (th/create-profile* 1 {:is-active true}) team (th/create-team* 1 {:profile-id (:id prof)}) @@ -418,3 +348,119 @@ (t/is (th/success? out)) (t/is (nil? (:result out))) (t/is (nil? res))))) + + +(t/deftest team-deletion-1 + (let [profile1 (th/create-profile* 1 {:is-active true}) + team (th/create-team* 1 {:profile-id (:id profile1)}) + pool (:app.db/pool th/*system*) + data {::th/type :delete-team + ::rpc/profile-id (:id profile1) + :team-id (:id team)}] + + ;; team is not deleted because it does not meet all + ;; conditions to be deleted. + (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] + (t/is (= 0 (:processed result)))) + + ;; query the list of teams + (let [data {::th/type :get-teams + ::rpc/profile-id (:id profile1)} + out (th/command! data)] + ;; (th/print-result! out) + (t/is (th/success? out)) + (let [result (:result out)] + (t/is (= 2 (count result))) + (t/is (= (:id team) (get-in result [1 :id]))) + (t/is (= (:default-team-id profile1) (get-in result [0 :id]))))) + + ;; Request team to be deleted + (let [params {::th/type :delete-team + ::rpc/profile-id (:id profile1) + :id (:id team)} + out (th/command! params)] + (t/is (th/success? out))) + + ;; query the list of teams after soft deletion + (let [data {::th/type :get-teams + ::rpc/profile-id (:id profile1)} + out (th/command! data)] + ;; (th/print-result! out) + (t/is (th/success? out)) + (let [result (:result out)] + (t/is (= 1 (count result))) + (t/is (= (:default-team-id profile1) (get-in result [0 :id]))))) + + ;; run permanent deletion (should be noop) + (let [result (th/run-task! :objects-gc {:min-age (dt/duration {:minutes 1})})] + (t/is (= 0 (:processed result)))) + + ;; query the list of projects after hard deletion + (let [data {::th/type :get-projects + ::rpc/profile-id (:id profile1) + :team-id (:id team)} + out (th/command! data)] + ;; (th/print-result! out) + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :not-found (:type edata))))) + + ;; run permanent deletion + (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] + (t/is (= 2 (:processed result)))) + + ;; query the list of projects of a after hard deletion + (let [data {::th/type :get-projects + ::rpc/profile-id (:id profile1) + :team-id (:id team)} + out (th/command! data)] + ;; (th/print-result! out) + + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :not-found (:type edata))))))) + + +(t/deftest team-deletion-2 + (let [storage (-> (:app.storage/storage th/*system*) + (assoc ::sto/backend :assets-fs)) + prof (th/create-profile* 1) + + team (th/create-team* 1 {:profile-id (:id prof)}) + + proj (th/create-project* 1 {:profile-id (:id prof) + :team-id (:id team)}) + file (th/create-file* 1 {:profile-id (:id prof) + :project-id (:default-project-id team) + :is-shared false}) + + mfile {:filename "sample.jpg" + :path (th/tempfile "backend_tests/test_files/sample.jpg") + :mtype "image/jpeg" + :size 312043}] + + + (let [params {::th/type :upload-file-media-object + ::rpc/profile-id (:id prof) + :file-id (:id file) + :is-local true + :name "testfile" + :content mfile} + + out (th/command! params)] + (t/is (nil? (:error out)))) + + (let [params {::th/type :delete-team + ::rpc/profile-id (:id prof) + :id (:id team)} + out (th/command! params)] + #_(th/print-result! out) + (t/is (nil? (:error out)))) + + (let [rows (th/db-exec! ["select * from team where id = ?" (:id team)])] + (t/is (= 1 (count rows))) + (t/is (dt/instant? (:deleted-at (first rows))))) + + (let [result (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 5 (:processed result)))) + )) diff --git a/backend/test/backend_tests/storage_test.clj b/backend/test/backend_tests/storage_test.clj index 5277544204..ccc0d08630 100644 --- a/backend/test/backend_tests/storage_test.clj +++ b/backend/test/backend_tests/storage_test.clj @@ -113,7 +113,7 @@ (let [res (th/run-task! :storage-gc-deleted {})] (t/is (= 1 (:deleted res)))) - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object;"])] + (let [res (th/db-exec-one! ["select count(*) from storage_object;"])] (t/is (= 2 (:count res)))))) (t/deftest test-touched-gc-task-1 @@ -156,29 +156,33 @@ (t/is (= (:media-id result-1) (:media-id result-2))) - ;; now we proceed to manually delete one file-media-object - (db/exec-one! th/*pool* ["delete from file_media_object where id = ?" (:id result-1)]) + (th/db-update! :file-media-object + {:deleted-at (dt/now)} + {:id (:id result-1)}) + + ;; run the objects gc task for permanent deletion + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) ;; check that we still have all the storage objects - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object"])] + (let [res (th/db-exec-one! ["select count(*) from storage_object"])] (t/is (= 2 (:count res)))) ;; now check if the storage objects are touched - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object where touched_at is not null"])] + (let [res (th/db-exec-one! ["select count(*) from storage_object where touched_at is not null"])] (t/is (= 2 (:count res)))) ;; run the touched gc task - (let [task (:app.storage/gc-touched-task th/*system*) - res (task {})] + (let [res (th/run-task! :storage-gc-touched {})] (t/is (= 2 (:freeze res))) (t/is (= 0 (:delete res)))) ;; now check that there are no touched objects - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object where touched_at is not null"])] + (let [res (th/db-exec-one! ["select count(*) from storage_object where touched_at is not null"])] (t/is (= 0 (:count res)))) ;; now check that all objects are marked to be deleted - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object where deleted_at is not null"])] + (let [res (th/db-exec-one! ["select count(*) from storage_object where deleted_at is not null"])] (t/is (= 0 (:count res))))))) @@ -231,31 +235,35 @@ (t/is (nil? (:error out2))) ;; run the touched gc task - (let [task (:app.storage/gc-touched-task th/*system*) - res (task {})] + (let [res (th/run-task! :storage-gc-touched {})] (t/is (= 5 (:freeze res))) (t/is (= 0 (:delete res))) (let [result-1 (:result out1) result-2 (:result out2)] - ;; now we proceed to manually delete one team-font-variant - (db/exec-one! th/*pool* ["delete from team_font_variant where id = ?" (:id result-2)]) + (th/db-update! :team-font-variant + {:deleted-at (dt/now)} + {:id (:id result-2)}) + + ;; run the objects gc task for permanent deletion + (let [res (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 1 (:processed res)))) ;; revert touched state to all storage objects - (db/exec-one! th/*pool* ["update storage_object set touched_at=now()"]) + (th/db-exec-one! ["update storage_object set touched_at=now()"]) ;; Run the task again - (let [res (task {})] + (let [res (th/run-task! :storage-gc-touched {})] (t/is (= 2 (:freeze res))) (t/is (= 3 (:delete res)))) ;; now check that there are no touched objects - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object where touched_at is not null"])] + (let [res (th/db-exec-one! ["select count(*) from storage_object where touched_at is not null"])] (t/is (= 0 (:count res)))) ;; now check that all objects are marked to be deleted - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object where deleted_at is not null"])] + (let [res (th/db-exec-one! ["select count(*) from storage_object where deleted_at is not null"])] (t/is (= 3 (:count res)))))))) (t/deftest test-touched-gc-task-3 @@ -289,28 +297,28 @@ result-2 (:result out2)] ;; now we proceed to manually mark all storage objects touched - (db/exec-one! th/*pool* ["update storage_object set touched_at=now()"]) + (th/db-exec! ["update storage_object set touched_at=now()"]) ;; run the touched gc task - (let [task (:app.storage/gc-touched-task th/*system*) - res (task {})] + (let [res (th/run-task! "storage-gc-touched" {:min-age 0})] (t/is (= 2 (:freeze res))) (t/is (= 0 (:delete res)))) ;; check that we have all object in the db - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object where deleted_at is null"])] - (t/is (= 2 (:count res))))) + (let [rows (th/db-exec! ["select * from storage_object"])] + (t/is (= 2 (count rows))))) ;; now we proceed to manually delete all file_media_object - (db/exec-one! th/*pool* ["delete from file_media_object"]) + (th/db-exec! ["update file_media_object set deleted_at = now()"]) + + (let [res (th/run-task! "objects-gc" {:min-age 0})] + (t/is (= 2 (:processed res)))) ;; run the touched gc task - (let [task (:app.storage/gc-touched-task th/*system*) - res (task {})] + (let [res (th/run-task! "storage-gc-touched" {:min-age 0})] (t/is (= 0 (:freeze res))) (t/is (= 2 (:delete res)))) ;; check that we have all no objects - (let [res (db/exec-one! th/*pool* ["select count(*) from storage_object where deleted_at is null"])] - (t/is (= 0 (:count res)))))) - + (let [rows (th/db-exec! ["select * from storage_object where deleted_at is null"])] + (t/is (= 0 (count rows)))))) From 3ae1a97bc99815b05eca6257478986756371810a Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 3 Jan 2024 12:20:42 +0100 Subject: [PATCH 14/35] :bug: Fix problem when duplicating/moving tracks --- common/src/app/common/types/shape/layout.cljc | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 183d16c8a2..3207724e12 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -622,7 +622,7 @@ (defn remove-cell-areas "Remove the areas in the given `index` before and after the index" [parent prop index] - (let [prop-span (if (= prop :column) :row-span :column-span) + (let [prop-span (if (= prop :column) :column-span :row-span) cells (if (= prop :column) (cells-by-column parent index) (cells-by-row parent index))] (->> cells (filter #(> (get % prop-span) 1)) @@ -654,7 +654,7 @@ "Remove the areas in the given `index` but only after the index." [parent prop index] (let [prop-span (if (= prop :column) :column-span :row-span) - cells (if (= type :column) (cells-by-column parent index) (cells-by-row parent index))] + cells (if (= prop :column) (cells-by-column parent index) (cells-by-row parent index))] (->> cells (filter #(> (get % prop-span) 1)) (reduce @@ -924,7 +924,7 @@ (cond-> parent move-content? (-> (remove-cell-areas prop (dec from-track)) - (remove-cell-areas prop (dec to-track)))) + (remove-cell-areas-after prop (- to-track 2)))) parent (reorder-grid-tracks parent tracks-props from-index to-index)] @@ -1376,24 +1376,26 @@ (cells-by-row parent index true)) ([parent index check-span?] (->> (:layout-grid-cells parent) - (filter (fn [[_ {:keys [row row-span]}]] - (if check-span? - (and (>= (inc index) row) - (< (inc index) (+ row row-span))) - (= (inc index) row)))) - (map second)))) + (vals) + (filter + (fn [{:keys [row row-span]}] + (if check-span? + (and (>= (inc index) row) + (< (inc index) (+ row row-span))) + (= (inc index) row))))))) (defn cells-by-column ([parent index] (cells-by-column parent index true)) ([parent index check-span?] (->> (:layout-grid-cells parent) - (filter (fn [[_ {:keys [column column-span]}]] - (if check-span? - (and (>= (inc index) column) - (< (inc index) (+ column column-span))) - (= (inc index) column)))) - (map second)))) + (vals) + (filter + (fn [{:keys [column column-span] :as cell}] + (if check-span? + (and (>= (inc index) column) + (< (inc index) (+ column column-span))) + (= (inc index) column))))))) (defn shapes-by-row ([parent index] From 6068ddc0ff219a58065008af38758d935e13f572 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 3 Jan 2024 14:40:40 +0100 Subject: [PATCH 15/35] :sparkles: Add delete with content option --- common/src/app/common/types/shape/layout.cljc | 4 +- .../app/main/data/workspace/shape_layout.cljs | 47 ++++++++++++------- .../main/ui/viewer/inspect/right_sidebar.scss | 1 + .../app/main/ui/workspace/context_menu.cljs | 14 ++++-- .../main/ui/workspace/sidebar/history.scss | 1 + frontend/translations/en.po | 6 +++ frontend/translations/es.po | 6 +++ 7 files changed, 58 insertions(+), 21 deletions(-) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 3207724e12..86aff113ed 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -923,8 +923,8 @@ parent (cond-> parent move-content? - (-> (remove-cell-areas prop (dec from-track)) - (remove-cell-areas-after prop (- to-track 2)))) + (-> (remove-cell-areas prop from-index) + (remove-cell-areas-after prop to-index))) parent (reorder-grid-tracks parent tracks-props from-index to-index)] diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index f5a1cb9368..2f8c397fa6 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -24,7 +24,7 @@ [app.main.data.workspace.grid-layout.editor :as dwge] [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.selection :as dwse] - [app.main.data.workspace.shapes :as dws] + [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [beicon.v2.core :as rx] @@ -170,18 +170,18 @@ group-index (cfh/get-index-replacement selected objects)] (rx/of (dwse/select-shapes ordered-ids) - (dws/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes))) + (dwsh/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes))) (cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1}) (create-layout-from-id new-shape-id type false) (dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto)) (dch/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix)) - (dws/delete-shapes page-id selected) + (dwsh/delete-shapes page-id selected) (ptk/data-event :layout/update [new-shape-id]) (dwu/commit-undo-transaction undo-id))) ;; Create Layout from selection (rx/of - (dws/create-artboard-from-selection new-shape-id) + (dwsh/create-artboard-from-selection new-shape-id) (cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1}) (create-layout-from-id new-shape-id type false) (dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto)) @@ -269,23 +269,38 @@ (dwu/commit-undo-transaction undo-id))))))) (defn remove-layout-track - [ids type index] + [ids type index & {:keys [with-shapes?] :or {with-shapes? false}}] (assert (#{:row :column} type)) (ptk/reify ::remove-layout-track ptk/WatchEvent - (watch [_ _ _] + (watch [_ state _] (let [undo-id (js/Symbol)] - (rx/of (dwu/start-undo-transaction undo-id) - (dch/update-shapes - ids - (fn [shape objects] - (case type - :row (ctl/remove-grid-row shape index objects) - :column (ctl/remove-grid-column shape index objects))) - {:with-objects? true}) - (ptk/data-event :layout/update ids) - (dwu/commit-undo-transaction undo-id)))))) + (let [objects (wsh/lookup-page-objects state) + + shapes-to-delete + (when with-shapes? + (->> ids + (mapcat + (fn [id] + (let [shape (get objects id)] + (if (= type :column) + (ctl/shapes-by-column shape index) + (ctl/shapes-by-row shape index))))) + (into #{})))] + (rx/of (dwu/start-undo-transaction undo-id) + (if shapes-to-delete + (dwsh/delete-shapes shapes-to-delete) + (rx/empty)) + (dch/update-shapes + ids + (fn [shape objects] + (case type + :row (ctl/remove-grid-row shape index objects) + :column (ctl/remove-grid-column shape index objects))) + {:with-objects? true}) + (ptk/data-event :layout/update ids) + (dwu/commit-undo-transaction undo-id))))))) (defn duplicate-layout-track [ids type index] diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss index 874935b245..f002dc630b 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss @@ -58,6 +58,7 @@ @include titleTipography; text-align: center; width: $s-200; + color: $df-secondary; } } .more-info-btn { diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index e8140696aa..1e22964543 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -548,20 +548,28 @@ (mf/use-callback (mf/deps grid-id type index) (fn [] - (st/emit! (dwsl/duplicate-layout-track [grid-id] type index))))] + (st/emit! (dwsl/duplicate-layout-track [grid-id] type index)))) + + do-delete-track-shapes + (mf/use-callback + (mf/deps grid-id type index) + (fn [] + (st/emit! (dwsl/remove-layout-track [grid-id] type index {:with-shapes? true}))))] (if (= type :column) [:* [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.duplicate") :on-click do-duplicate-track}] [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-before") :on-click do-add-track-before}] [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-after") :on-click do-add-track-after}] - [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.delete") :on-click do-delete-track}]] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.delete") :on-click do-delete-track}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.delete-shapes") :on-click do-delete-track-shapes}]] [:* [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.duplicate") :on-click do-duplicate-track}] [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-before") :on-click do-add-track-before}] [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-after") :on-click do-add-track-after}] - [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.delete") :on-click do-delete-track}]]))) + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.delete") :on-click do-delete-track}] + [:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.delete-shapes") :on-click do-delete-track-shapes}]]))) (mf/defc grid-cells-context-menu [{:keys [mdata] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.scss b/frontend/src/app/main/ui/workspace/sidebar/history.scss index 9a23cda6cc..bafe0cff74 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/history.scss @@ -95,6 +95,7 @@ } .history-entry-summary-text { margin: 0 $s-8; + color: $df-primary; } .history-entry-summary-button { opacity: $op-0; diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 3d32f6632e..b01c7a11c4 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5070,6 +5070,9 @@ msgstr "Add 1 column to the right" msgid "workspace.context-menu.grid-track.column.delete" msgstr "Delete column" +msgid "workspace.context-menu.grid-track.column.delete-shapes" +msgstr "Delete column and shapes" + msgid "workspace.context-menu.grid-track.row.duplicate" msgstr "Duplicate row" @@ -5082,6 +5085,9 @@ msgstr "Add 1 row bellow" msgid "workspace.context-menu.grid-track.row.delete" msgstr "Delete row" +msgid "workspace.context-menu.grid-track.row.delete-shapes" +msgstr "Delete row and shapes" + msgid "workspace.context-menu.grid-cells.merge" msgstr "Merge cells" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 9fcdbdbcf0..8845dc4848 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5159,6 +5159,9 @@ msgstr "Añadir 1 columna a la derecha" msgid "workspace.context-menu.grid-track.column.delete" msgstr "Borrar columna" +msgid "workspace.context-menu.grid-track.column.delete-shapes" +msgstr "Borrar columna con el contenido" + msgid "workspace.context-menu.grid-track.row.duplicate" msgstr "Duplicar fila" @@ -5171,6 +5174,9 @@ msgstr "Añadir 1 fila debajo" msgid "workspace.context-menu.grid-track.row.delete" msgstr "Borrar fila" +msgid "workspace.context-menu.grid-track.row.delete-shapes" +msgstr "Borrar fila con el contenido" + msgid "workspace.context-menu.grid-cells.merge" msgstr "Fusionar celdas" From 009556b8f7e9f30e5b24095ef2fc5c14590cfe33 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 3 Jan 2024 16:47:14 +0100 Subject: [PATCH 16/35] :sparkles: Improve grid cell selection --- common/src/app/common/types/shape/layout.cljc | 17 ++++++++++ .../data/workspace/grid_layout/editor.cljs | 33 +++++++++++++++---- .../app/main/ui/workspace/context_menu.cljs | 4 ++- .../viewport/grid_layout_editor.cljs | 15 +++++++-- 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 86aff113ed..08645a098a 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -1397,6 +1397,23 @@ (< (inc index) (+ column column-span))) (= (inc index) column))))))) +(defn cells-in-area + [parent first-row last-row first-column last-column] + (->> (:layout-grid-cells parent) + (vals) + (filter + (fn [{:keys [row column row-span column-span] :as cell}] + (and + (or (<= row first-row (+ row row-span -1)) + (<= row last-row (+ row row-span -1)) + (<= first-row row last-row) + (<= first-row (+ row row-span -1) last-row)) + + (or (<= column first-column (+ column column-span -1)) + (<= column last-column (+ column column-span -1)) + (<= first-column column last-column) + (<= first-column (+ column column-span -1) last-column))))))) + (defn shapes-by-row ([parent index] (shapes-by-row parent index true)) diff --git a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs index dc6e99fa59..9af194119f 100644 --- a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs +++ b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs @@ -6,6 +6,7 @@ (ns app.main.data.workspace.grid-layout.editor (:require + [app.common.data.macros :as dm] [app.common.geom.rect :as grc] [app.common.types.shape.layout :as ctl] [app.main.data.workspace.state-helpers :as wsh] @@ -25,14 +26,34 @@ (conj hover-set cell-id) (disj hover-set cell-id)))))))) -(defn select-grid-cell - [grid-id cell-id add?] - (ptk/reify ::select-grid-cell +(defn add-to-selection + ([grid-id cell-id] + (add-to-selection grid-id cell-id false)) + ([grid-id cell-id shift?] + (ptk/reify ::add-to-selection + ptk/UpdateEvent + (update [_ state] + (if shift? + (let [objects (wsh/lookup-page-objects state) + grid (get objects grid-id) + selected (or (dm/get-in state [:workspace-grid-edition grid-id :selected]) #{}) + selected (into selected [cell-id]) + cells (->> selected (map #(dm/get-in grid [:layout-grid-cells %]))) + + {:keys [first-row last-row first-column last-column]} (ctl/cells-coordinates cells) + new-selected + (into #{} + (map :id) + (ctl/cells-in-area grid first-row last-row first-column last-column))] + (assoc-in state [:workspace-grid-edition grid-id :selected] new-selected)) + (update-in state [:workspace-grid-edition grid-id :selected] (fnil conj #{}) cell-id)))))) + +(defn set-selection + [grid-id cell-id] + (ptk/reify ::set-selection ptk/UpdateEvent (update [_ state] - (if add? - (update-in state [:workspace-grid-edition grid-id :selected] (fnil conj #{}) cell-id) - (assoc-in state [:workspace-grid-edition grid-id :selected] #{cell-id}))))) + (assoc-in state [:workspace-grid-edition grid-id :selected] #{cell-id})))) (defn remove-selection [grid-id cell-id] diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 1e22964543..af84fffa69 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -576,6 +576,7 @@ (let [{:keys [grid cells]} mdata single? (= (count cells) 1) + can-merge? (mf/use-memo (mf/deps cells) @@ -603,7 +604,8 @@ :on-click do-merge-cells}]) [:& menu-entry {:title (tr "workspace.context-menu.grid-cells.create-board") - :on-click do-create-board}]])) + :on-click do-create-board + :disabled (and (not single?) (not can-merge?))}]])) (mf/defc context-menu diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index ddc740d96d..7b99e9f618 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -337,10 +337,19 @@ (mf/use-callback (mf/deps (:id shape) (:id cell) selected?) (fn [event] - (when (or (dom/left-mouse? event) (not selected?)) - (if (and (kbd/shift? event) selected?) + (when (dom/left-mouse? event) + (cond + (and selected? (or (kbd/mod? event) (kbd/shift? event))) (st/emit! (dwge/remove-selection (:id shape) (:id cell))) - (st/emit! (dwge/select-grid-cell (:id shape) (:id cell) (kbd/shift? event))))))) + + (and (not selected?) (kbd/mod? event)) + (st/emit! (dwge/add-to-selection (:id shape) (:id cell))) + + (and (not selected?) (kbd/shift? event)) + (st/emit! (dwge/add-to-selection (:id shape) (:id cell) true)) + + :else + (st/emit! (dwge/set-selection (:id shape) (:id cell))))))) handle-context-menu (mf/use-callback From 3aadf00a6fce78228a013397e9b21c6a9b9a4778 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 4 Jan 2024 09:52:09 +0100 Subject: [PATCH 17/35] :bug: Fix problem with thumbnails for empty pages --- frontend/src/app/main/render.cljs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 5b8620b462..c6bf57e9ab 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -67,17 +67,24 @@ (defn- calculate-dimensions [objects aspect-ratio] - (let [bounds - (->> (ctst/get-root-objects objects) - (map (partial gsb/get-object-bounds objects)) - (grc/join-rects))] - (-> bounds - (update :x mth/finite 0) - (update :y mth/finite 0) - (update :width mth/finite 100000) - (update :height mth/finite 100000) - (grc/update-rect :position) - (grc/fix-aspect-ratio aspect-ratio)))) + (let [root-objects (ctst/get-root-objects objects)] + (if (empty? root-objects) + ;; Empty page, we create an arbitrary rect for the thumbnail + (-> (grc/make-rect {:x 0 :y 0 :width 100 :height 100}) + (grc/update-rect :position) + (grc/fix-aspect-ratio aspect-ratio)) + + (let [bounds + (->> root-objects + (map (partial gsb/get-object-bounds objects)) + (grc/join-rects))] + (-> bounds + (update :x mth/finite 0) + (update :y mth/finite 0) + (update :width mth/finite 100000) + (update :height mth/finite 100000) + (grc/update-rect :position) + (grc/fix-aspect-ratio aspect-ratio)))))) (declare shape-wrapper-factory) @@ -201,6 +208,7 @@ (let [objects (:objects data) shapes (cfh/get-immediate-children objects) dim (calculate-dimensions objects aspect-ratio) + _ (prn ">>DIM" dim) vbox (format-viewbox dim) bgcolor (dm/get-in data [:options :background] default-color) From 79c2a6c5d55cb94b494a23ccb0a12dcb793b934c Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 2 Jan 2024 08:34:46 +0100 Subject: [PATCH 18/35] :bug: Fix round for both ends of path --- frontend/src/app/main/ui/shapes/attrs.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index 14bee97258..e2bcf1156b 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -124,7 +124,7 @@ (not= :inner alignment) (not= :outer alignment) (not= :dotted style)) - (obj/set! attrs "strokeLinecap" caps-start) + (obj/set! attrs "strokeLinecap" (name caps-start)) (= :dotted style) (obj/set! attrs "strokeLinecap" "round")) From 5ad31a878b7d0ada1aa57dc097948415f119cfe6 Mon Sep 17 00:00:00 2001 From: Aitor Date: Wed, 3 Jan 2024 10:02:13 +0100 Subject: [PATCH 19/35] :bug: Fix rasterizer not loading embedded styles --- frontend/src/app/rasterizer.cljs | 54 +++++++++++++++++++++++++------- frontend/src/app/util/dom.cljs | 4 +++ 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/rasterizer.cljs b/frontend/src/app/rasterizer.cljs index d6eeb474ca..157b57a653 100644 --- a/frontend/src/app/rasterizer.cljs +++ b/frontend/src/app/rasterizer.cljs @@ -96,10 +96,16 @@ :method :get :mode :cors :omit-default-headers true}) - (rx/map :body) - (rx/mapcat wapi/read-file-as-data-url) - (rx/tap (fn [data-uri] - (.set data-uri-cache uri (wapi/create-blob data-uri "text/plain"))))))) + (rx/catch (fn [cause] + (log/error :hint "fetching data uri" + :cause cause) + (rx/of nil))) + (rx/mapcat (fn [response] + (if (nil? response) + (rx/of uri) + (->> (rx/of (:body response)) + (rx/mapcat wapi/read-file-as-data-url) + (rx/tap (fn [data-uri] (.set data-uri-cache uri (wapi/create-blob data-uri "text/plain"))))))))))) (defn- svg-update-image! "Updates an image in an SVG to a Data URI." @@ -128,27 +134,53 @@ (dom/append-child! style (dom/create-text svg styles)) (dom/append-child! doc style))) -(defn- svg-resolve-styles! - "Resolves all fonts in an SVG to Data URIs." - [svg styles] +(defn- svg-resolve-external-resources + "Resolves all external resources in an SVG to Data URIs." + [styles] (->> (rx/from (re-seq #"url\((https?://[^)]+)\)" styles)) (rx/map second) (rx/mapcat (fn [url] - (->> (fetch-as-data-uri url) - (rx/map (fn [uri] [url uri]))))) - + (->> (fetch-as-data-uri url) + (rx/map (fn [uri] [url uri]))))) (rx/reduce (fn [styles [url uri]] (str/replace styles url uri)) - styles) + styles))) + +(defn- svg-resolve-styles! + "Resolves all fonts in an SVG to Data URIs." + [svg styles] + (->> (svg-resolve-external-resources styles) (rx/tap (partial svg-add-style! svg)) (rx/ignore))) +(defn- svg-resolve-inline-styles! + "Resolves all inline styles in an SVG to Data URIs." + [svg] + (->> (rx/from (dom/query-all svg "[style]")) + (rx/mapcat (fn [node] + (let [styles (dom/get-attribute node "style")] + (->> (svg-resolve-external-resources styles) + (rx/tap (fn [styles] (dom/set-attribute! node "style" styles))))))) + (rx/ignore))) + +(defn- svg-resolve-style-elements! + "Resolves all style elements in an SVG to Data URIs." + [svg] + (->> (rx/from (dom/query-all svg "style")) + (rx/mapcat (fn [node] + (let [styles (dom/get-text node)] + (->> (svg-resolve-external-resources styles) + (rx/tap (fn [styles] (dom/set-text! node styles))))))) + (rx/ignore))) + (defn- svg-resolve-all! "Resolves all images and fonts in an SVG to Data URIs." [svg styles] (rx/concat (svg-resolve-images! svg) (svg-resolve-styles! svg styles) + (svg-resolve-inline-styles! svg) + (svg-resolve-style-elements! svg) (rx/of svg))) (defn- svg-parse diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index 8b04784789..998a581ebc 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -504,6 +504,10 @@ (.setAttribute node property value)) node) +(defn get-text [^js node] + (when (some? node) + (.-textContent node))) + (defn set-text! [^js node text] (when (some? node) (set! (.-textContent node) text)) From 824e7d76ae4996d4c088dfd595818e52445f52a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Wed, 3 Jan 2024 15:49:00 +0100 Subject: [PATCH 20/35] :bug: Fix blur icon changing size on hover --- .../src/app/main/ui/workspace/sidebar/options/menus/blur.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss index 87f3b39d84..6bed44856a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss @@ -75,7 +75,6 @@ .action-btn { @extend .button-tertiary; box-sizing: border-box; - border: $s-1 solid var(--button-tertiary-background-color-rest); height: $s-32; width: $s-28; svg { From b3684990f1a25c8c2e5d911ec8a9a51404128bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Wed, 3 Jan 2024 16:34:50 +0100 Subject: [PATCH 21/35] :bug: Fix sizes of dropdowns in the export section --- .../sidebar/options/menus/exports.scss | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss index 42ecf713b6..6bbb39afd9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss @@ -48,33 +48,10 @@ } .element-group { - @include flexRow; - .input-wrapper { - @include flexRow; - .format-select { - width: $s-60; - padding: 0; - .dropdown-upwards { - bottom: $s-36; - width: $s-80; - top: unset; - } - } - .size-select { - width: $s-60; - padding: 0; - .dropdown-upwards { - bottom: $s-36; - top: unset; - width: $s-80; - } - } - .suffix-input { - @extend .input-element; - min-width: $s-92; - flex-grow: 1; - } - } + display: grid; + grid-template-columns: repeat(8, 1fr); + column-gap: $s-4; + .action-btn { @extend .button-tertiary; height: $s-32; @@ -85,6 +62,38 @@ } } +.input-wrapper { + grid-column: span 7; + display: grid; + grid-template-columns: subgrid; +} + +.format-select { + grid-column: span 2; + padding: 0; + + .dropdown-upwards { + bottom: $s-36; + width: $s-80; + top: unset; + } +} + +.size-select { + grid-column: span 2; + padding: 0; + .dropdown-upwards { + bottom: $s-36; + top: unset; + width: $s-80; + } +} + +.suffix-input { + grid-column: span 3; + @extend .input-element; +} + .export-btn { @extend .button-secondary; @include tabTitleTipography; From 7a3525febc4c064689bb0a50332c0289699028ee Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 3 Jan 2024 12:04:56 +0100 Subject: [PATCH 22/35] :recycle: Remove new-css-system from right sidebar elements --- .../styles/common/refactor/design-tokens.scss | 5 + frontend/resources/styles/main-default.scss | 1 - .../partials/sidebar-document-history.scss | 220 ++++++------- .../main/ui/viewer/inspect/attributes.cljs | 85 ++--- .../src/app/main/ui/viewer/inspect/code.cljs | 185 ++++------- .../src/app/main/ui/viewer/inspect/code.scss | 139 ++++---- .../main/ui/viewer/inspect/right_sidebar.cljs | 171 ++++------ .../main/ui/viewer/inspect/right_sidebar.scss | 122 +++---- frontend/src/app/main/ui/workspace.cljs | 4 +- frontend/src/app/main/ui/workspace.scss | 22 ++ .../src/app/main/ui/workspace/comments.cljs | 160 +++------- .../src/app/main/ui/workspace/comments.scss | 1 + .../main/ui/workspace/sidebar/history.cljs | 20 +- .../main/ui/workspace/sidebar/history.scss | 2 +- .../ui/workspace/sidebar/options/page.cljs | 51 +-- .../sidebar/options/rows/color_row.cljs | 205 ++++-------- .../sidebar/options/rows/color_row.scss | 301 +++++++++--------- .../sidebar/options/rows/input_row.cljs | 72 ----- .../sidebar/options/shapes/group.cljs | 7 +- .../sidebar/options/shapes/multiple.cljs | 7 +- .../main/ui/workspace/viewport/top_bar.cljs | 28 +- .../main/ui/workspace/viewport/widgets.cljs | 9 +- .../main/ui/workspace/viewport/widgets.scss | 64 ++++ 23 files changed, 800 insertions(+), 1081 deletions(-) delete mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs create mode 100644 frontend/src/app/main/ui/workspace/viewport/widgets.scss diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index f9c95e3f09..c9717d2e24 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -305,6 +305,11 @@ --resize-area-background-color: var(--color-background-primary); --resize-area-border-color: var(--color-background-quaternary); + --flow-tag-background-color: var(--color-background-tertiary); + --flow-tag-foreground-color: var(--color-foreground-secondary); + --flow-tag-background-color-hover: var(--color-accent-primary); + --flow-tag-foreground-color-hover: var(--color-background-primary); + // VIEWER --viewer-background-color: var(--color-background-secondary); --viewer-paginator-background-color: var(--color-background-tertiary); diff --git a/frontend/resources/styles/main-default.scss b/frontend/resources/styles/main-default.scss index 32288c6278..4ce046332b 100644 --- a/frontend/resources/styles/main-default.scss +++ b/frontend/resources/styles/main-default.scss @@ -70,7 +70,6 @@ @import "main/partials/loader"; @import "main/partials/project-bar"; @import "main/partials/sidebar"; -@import "main/partials/sidebar-document-history"; @import "main/partials/tab-container"; @import "main/partials/tool-bar"; @import "main/partials/user-settings"; diff --git a/frontend/resources/styles/main/partials/sidebar-document-history.scss b/frontend/resources/styles/main/partials/sidebar-document-history.scss index a8e00d41cc..582d7f300d 100644 --- a/frontend/resources/styles/main/partials/sidebar-document-history.scss +++ b/frontend/resources/styles/main/partials/sidebar-document-history.scss @@ -4,136 +4,136 @@ // // Copyright (c) KALEIDOS INC -.history-debug-overlay { - background: $color-gray-50; - bottom: 0; - max-height: 500px; - overflow-y: auto; - position: absolute; - width: 500px; - z-index: 1000; -} +// .history-debug-overlay { +// background: $color-gray-50; +// bottom: 0; +// max-height: 500px; +// overflow-y: auto; +// position: absolute; +// width: 500px; +// z-index: 1000; +// } -.history-toolbox { - display: flex; - flex-direction: column; -} +// .history-toolbox { +// display: flex; +// flex-direction: column; +// } -.history-toolbox-title { - color: $color-gray-10; - font-size: $fs14; - padding: 0.5rem; -} +// .history-toolbox-title { +// color: $color-gray-10; +// font-size: $fs14; +// padding: 0.5rem; +// } -.history-entry-empty { - display: flex; - flex-direction: column; - align-items: center; - padding: 1rem; +// .history-entry-empty { +// display: flex; +// flex-direction: column; +// align-items: center; +// padding: 1rem; - .history-entry-empty-icon { - margin-bottom: 1rem; - svg { - width: 32px; - height: 32px; - fill: $color-gray-40; - } - } +// .history-entry-empty-icon { +// margin-bottom: 1rem; +// svg { +// width: 32px; +// height: 32px; +// fill: $color-gray-40; +// } +// } - .history-entry-empty-msg { - color: $color-gray-30; - font-size: $fs12; - } -} +// .history-entry-empty-msg { +// color: $color-gray-30; +// font-size: $fs12; +// } +// } -.history-entries { - font-size: $fs12; - color: $color-gray-20; - fill: $color-gray-20; - height: 100%; - overflow-x: hidden; - overflow-y: auto; -} +// .history-entries { +// font-size: $fs12; +// color: $color-gray-20; +// fill: $color-gray-20; +// height: 100%; +// overflow-x: hidden; +// overflow-y: auto; +// } -.history-entry { - border: 1px solid $color-gray-60; - border-radius: $br4; - margin: 0.5rem; - display: flex; - flex-direction: column; - padding: 0.5rem; - cursor: pointer; +// .history-entry { +// border: 1px solid $color-gray-60; +// border-radius: $br4; +// margin: 0.5rem; +// display: flex; +// flex-direction: column; +// padding: 0.5rem; +// cursor: pointer; - transition: border 0.2s; +// transition: border 0.2s; - &.disabled { - opacity: 0.5; - } +// &.disabled { +// opacity: 0.5; +// } - &.current { - background-color: $color-gray-60; - } +// &.current { +// background-color: $color-gray-60; +// } - &.hover { - border-color: $color-primary; - } -} +// &.hover { +// border-color: $color-primary; +// } +// } -.history-entry-summary { - display: flex; - flex-direction: row; - align-items: center; +// .history-entry-summary { +// display: flex; +// flex-direction: row; +// align-items: center; - * { - display: flex; - } -} +// * { +// display: flex; +// } +// } -.history-entry-summary-icon { - svg { - width: 16px; - height: 16px; - } -} +// .history-entry-summary-icon { +// svg { +// width: 16px; +// height: 16px; +// } +// } -.history-entry-summary-text { - flex: 1; - margin: 0 0.5rem; - margin-top: 2px; -} +// .history-entry-summary-text { +// flex: 1; +// margin: 0 0.5rem; +// margin-top: 2px; +// } -.history-entry-summary-button { - opacity: 0; - transition: transform 0.2s; +// .history-entry-summary-button { +// opacity: 0; +// transition: transform 0.2s; - svg { - width: 12px; - height: 12px; - } +// svg { +// width: 12px; +// height: 12px; +// } - .show-detail &, - .hover & { - opacity: 1; - } +// .show-detail &, +// .hover & { +// opacity: 1; +// } - .show-detail & { - transform: rotate(90deg); - } -} +// .show-detail & { +// transform: rotate(90deg); +// } +// } -.history-entry-detail { - display: none; +// .history-entry-detail { +// display: none; - .show-detail & { - display: block; - padding: 1rem 0 0.5rem 0; - } +// .show-detail & { +// display: block; +// padding: 1rem 0 0.5rem 0; +// } - .history-entry-details-list { - margin: 0; +// .history-entry-details-list { +// margin: 0; - li { - margin-bottom: 0.5rem; - } - } -} +// li { +// margin-bottom: 0.5rem; +// } +// } +// } diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes.cljs index 74bf4bcf98..9798af6777 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes.cljs @@ -8,7 +8,6 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.types.components-list :as ctkl] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.viewer.inspect.annotation :refer [annotation]] [app.main.ui.viewer.inspect.attributes.blur :refer [blur-panel]] @@ -36,65 +35,35 @@ (mf/defc attributes [{:keys [page-id file-id shapes frame from libraries share-id objects]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - shapes (hooks/use-equal-memo shapes) + (let [shapes (hooks/use-equal-memo shapes) type (if (= (count shapes) 1) (-> shapes first :type) :multiple) options (type->options type) content (when (= (count shapes) 1) (ctkl/get-component-annotation (first shapes) libraries))] - (if new-css-system - [:div {:class (stl/css :element-options)} - (for [[idx option] (map-indexed vector options)] - [:> (case option - :geometry geometry-panel - :layout layout-panel - :layout-element layout-element-panel - :fill fill-panel - :stroke stroke-panel - :shadow shadow-panel - :blur blur-panel - :image image-panel - :text text-panel - :svg svg-panel) - {:key idx - :shapes shapes - :objects objects - :frame frame - :from from}]) - (when content - [:& annotation {:content content}]) - [:& exports - {:shapes shapes - :type type - :page-id page-id - :file-id file-id - :share-id share-id}]] - - - [:div.element-options - (for [[idx option] (map-indexed vector options)] - [:> (case option - :geometry geometry-panel - :layout layout-panel - :layout-element layout-element-panel - :fill fill-panel - :stroke stroke-panel - :shadow shadow-panel - :blur blur-panel - :image image-panel - :text text-panel - :svg svg-panel) - {:key idx - :shapes shapes - :objects objects - :frame frame - :from from}]) - (when content - [:& annotation {:content content}]) - [:& exports - {:shapes shapes - :type type - :page-id page-id - :file-id file-id - :share-id share-id}]]))) + [:div {:class (stl/css :element-options)} + (for [[idx option] (map-indexed vector options)] + [:> (case option + :geometry geometry-panel + :layout layout-panel + :layout-element layout-element-panel + :fill fill-panel + :stroke stroke-panel + :shadow shadow-panel + :blur blur-panel + :image image-panel + :text text-panel + :svg svg-panel) + {:key idx + :shapes shapes + :objects objects + :frame frame + :from from}]) + (when content + [:& annotation {:content content}]) + [:& exports + {:shapes shapes + :type type + :page-id page-id + :file-id file-id + :share-id share-id}]])) diff --git a/frontend/src/app/main/ui/viewer/inspect/code.cljs b/frontend/src/app/main/ui/viewer/inspect/code.cljs index b80df099dd..205ff04f32 100644 --- a/frontend/src/app/main/ui/viewer/inspect/code.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/code.cljs @@ -20,7 +20,6 @@ [app.main.ui.components.code-block :refer [code-block]] [app.main.ui.components.copy-button :refer [copy-button]] [app.main.ui.components.select :refer [select]] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.hooks.resize :refer [use-resize-hook]] [app.main.ui.icons :as i] @@ -100,8 +99,7 @@ (mf/defc code [{:keys [shapes frame on-expand from]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - style-type* (mf/use-state "css") + (let [style-type* (mf/use-state "css") markup-type* (mf/use-state "html") fontfaces-css* (mf/use-state nil) images-data* (mf/use-state nil) @@ -232,135 +230,80 @@ (fn [result] (reset! images-data* result))))) - (if new-css-system - [:div {:class (stl/css :element-options)} - [:div {:class (stl/css :attributes-block)} - [:button {:class (stl/css :download-button) - :on-click handle-copy-all-code} - "Copy all code"]] + [:div {:class (stl/css :element-options)} + [:div {:class (stl/css :attributes-block)} + [:button {:class (stl/css :download-button) + :on-click handle-copy-all-code} + "Copy all code"]] - #_[:div.attributes-block - [:button.download-button {:on-click handle-open-review} - "Preview"]] + #_[:div.attributes-block + [:button.download-button {:on-click handle-open-review} + "Preview"]] - [:div {:class (stl/css :code-block)} - [:div {:class (stl/css :code-row-lang)} - [:button {:class (stl/css :toggle-btn) - :data-type "css" - :on-click handle-collapse} - [:span {:class (stl/css-case - :collapsabled-icon true - :rotated collapsed-css?)} - i/arrow-refactor]] + [:div {:class (stl/css :code-block)} + [:div {:class (stl/css :code-row-lang)} + [:button {:class (stl/css :toggle-btn) + :data-type "css" + :on-click handle-collapse} + [:span {:class (stl/css-case + :collapsabled-icon true + :rotated collapsed-css?)} + i/arrow-refactor]] - [:& select {:default-value style-type - :class (stl/css :code-lang-select) - :options [{:label "CSS" :value "css"}]}] + [:& select {:default-value style-type + :class (stl/css :code-lang-select) + :on-change set-style + :options [{:label "CSS" :value "css"}]}] - [:div {:class (stl/css :action-btns)} - [:button {:class (stl/css :expand-button) - :on-click on-expand} - i/code-refactor] + [:div {:class (stl/css :action-btns)} + [:button {:class (stl/css :expand-button) + :on-click on-expand} + i/code-refactor] - [:& copy-button {:data #(replace-map style-code images-data) - :on-copied on-style-copied}]]] + [:& copy-button {:data #(replace-map style-code images-data) + :on-copied on-style-copied}]]] - (when-not collapsed-css? - [:div {:class (stl/css :code-row-display) - :style #js {"--code-height" (str (or style-size 400) "px")}} - [:& code-block {:type style-type - :code style-code}]]) - - [:div {:class (stl/css :resize-area) - :on-pointer-down on-style-pointer-down - :on-lost-pointer-capture on-style-lost-pointer-capture - :on-pointer-move on-style-pointer-move}]] - - [:div {:class (stl/css :code-block)} - [:div {:class (stl/css :code-row-lang)} - [:button {:class (stl/css :toggle-btn) - :data-type "markup" - :on-click handle-collapse} - [:span {:class (stl/css-case - :collapsabled-icon true - :rotated collapsed-markup?)} - i/arrow-refactor]] - [:& select {:default-value markup-type - :class (stl/css :code-lang-select) - :options [{:label "HTML" :value "html"} - {:label "SVG" :value "svg"}] - :on-change set-markup}] - - [:div {:class (stl/css :action-btns)} - [:button {:class (stl/css :expand-button) - :on-click on-expand} - i/code-refactor] - - [:& copy-button {:data #(replace-map markup-code images-data) - :on-copied on-markup-copied}]]] - - (when-not collapsed-markup? - [:div {:class (stl/css :code-row-display) - :style #js {"--code-height" (str (or markup-size 400) "px")}} - [:& code-block {:type markup-type - :code markup-code}]]) - - [:div {:class (stl/css :resize-area) - :on-pointer-down on-markup-pointer-down - :on-lost-pointer-capture on-markup-lost-pointer-capture - :on-pointer-move on-markup-pointer-move}]]] - - - - [:div.element-options - [:div.attributes-block - [:button.download-button {:on-click handle-copy-all-code} - "Copy all code"]] - - #_[:div.attributes-block - [:button.download-button {:on-click handle-open-review} - "Preview"]] - - [:div.code-block - [:div.code-row-lang - [:& select {:default-value style-type - :class "custom-select" - :options [{:label "CSS" :value "css"}] - :on-change set-style}] - [:button.expand-button - {:on-click on-expand} - i/full-screen] - - [:& copy-button {:data #(replace-map style-code images-data) - :on-copied on-style-copied}]] - - [:div.code-row-display {:style #js {"--code-height" (str (or style-size 400) "px")}} + (when-not collapsed-css? + [:div {:class (stl/css :code-row-display) + :style #js {"--code-height" (str (or style-size 400) "px")}} [:& code-block {:type style-type - :code style-code}]] + :code style-code}]]) - [:div.resize-area {:on-pointer-down on-style-pointer-down - :on-lost-pointer-capture on-style-lost-pointer-capture - :on-pointer-move on-style-pointer-move}]] + [:div {:class (stl/css :resize-area) + :on-pointer-down on-style-pointer-down + :on-lost-pointer-capture on-style-lost-pointer-capture + :on-pointer-move on-style-pointer-move}]] - [:div.code-block - [:div.code-row-lang - [:& select {:default-value markup-type - :class "input-option" - :options [{:label "HTML" :value "html"} - {:label "SVG" :value "svg"}] - :on-change set-markup}] + [:div {:class (stl/css :code-block)} + [:div {:class (stl/css :code-row-lang)} + [:button {:class (stl/css :toggle-btn) + :data-type "markup" + :on-click handle-collapse} + [:span {:class (stl/css-case + :collapsabled-icon true + :rotated collapsed-markup?)} + i/arrow-refactor]] + [:& select {:default-value markup-type + :class (stl/css :code-lang-select) + :options [{:label "HTML" :value "html"} + {:label "SVG" :value "svg"}] + :on-change set-markup}] - [:button.expand-button - {:on-click on-expand} - i/full-screen] + [:div {:class (stl/css :action-btns)} + [:button {:class (stl/css :expand-button) + :on-click on-expand} + i/code-refactor] - [:& copy-button {:data #(replace-map markup-code images-data) - :on-copied on-markup-copied}]] + [:& copy-button {:data #(replace-map markup-code images-data) + :on-copied on-markup-copied}]]] - [:div.code-row-display {:style #js {"--code-height" (str (or markup-size 400) "px")}} + (when-not collapsed-markup? + [:div {:class (stl/css :code-row-display) + :style #js {"--code-height" (str (or markup-size 400) "px")}} [:& code-block {:type markup-type - :code markup-code}]] + :code markup-code}]]) - [:div.resize-area {:on-pointer-down on-markup-pointer-down - :on-lost-pointer-capture on-markup-lost-pointer-capture - :on-pointer-move on-markup-pointer-move}]]]))) + [:div {:class (stl/css :resize-area) + :on-pointer-down on-markup-pointer-down + :on-lost-pointer-capture on-markup-lost-pointer-capture + :on-pointer-move on-markup-pointer-move}]]])) diff --git a/frontend/src/app/main/ui/viewer/inspect/code.scss b/frontend/src/app/main/ui/viewer/inspect/code.scss index 3524f40a03..9f7c37b5e7 100644 --- a/frontend/src/app/main/ui/viewer/inspect/code.scss +++ b/frontend/src/app/main/ui/viewer/inspect/code.scss @@ -12,80 +12,85 @@ height: 100%; overflow: hidden; padding-bottom: $s-16; +} - .attributes-block { - .download-button { - @extend .button-secondary; - @include tabTitleTipography; - height: $s-32; - width: 100%; - margin: $s-8 0; - } - } - .code-block { - @include codeTypography; - display: flex; - flex-direction: column; - flex: 1; +.download-button { + @extend .button-secondary; + @include tabTitleTipography; + height: $s-32; + width: 100%; + margin: $s-8 0; +} + +.code-block { + @include codeTypography; + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + min-height: 0; + overflow: hidden; + padding: 0 $s-4 $s-8 0; + + pre { + border-radius: $br-8; + padding: $s-16; + max-height: var(--code-height); + overflow: auto; height: 100%; - min-height: 0; - overflow: hidden; - padding: 0 $s-4 $s-8 0; + } - pre { - border-radius: $br-8; - padding: $s-16; - max-height: var(--code-height); - overflow: auto; - height: 100%; - } + // Overrides background setted in the theme + :global(.hljs) { + background: $db-tertiary; + } +} - // Overrides background setted in the theme - :global(.hljs) { - background: $db-tertiary; - } - } - .code-row-lang { - display: flex; - justify-content: space-between; - gap: $s-4; - width: 100%; - } - .code-lang { - @include tabTitleTipography; - display: flex; - align-items: center; - } - .action-btns { - display: flex; - gap: $s-4; - flex: 1; - justify-content: end; - .expand-button { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - } - } - .code-lang-select { - @include tabTitleTipography; - width: $s-72; - border: $s-1 solid transparent; - background-color: transparent; - color: var(--menu-foreground-color-disabled); - } - .code-row-display { - flex: 1; - min-height: 0; - overflow: hidden; - padding-bottom: $s-8; +.code-row-lang { + display: flex; + justify-content: space-between; + gap: $s-4; + width: 100%; +} + +.code-lang { + @include tabTitleTipography; + display: flex; + align-items: center; +} + +.action-btns { + display: flex; + gap: $s-4; + flex: 1; + justify-content: end; +} + +.expand-button { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); } } +.code-lang-select { + @include tabTitleTipography; + width: $s-72; + border: $s-1 solid transparent; + background-color: transparent; + color: var(--menu-foreground-color-disabled); +} + +.code-row-display { + flex: 1; + min-height: 0; + overflow: hidden; + padding-bottom: $s-8; +} + .toggle-btn { @include buttonStyle; display: flex; diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs index d5fe584b74..ea62c3111b 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs @@ -10,11 +10,8 @@ [app.common.data.macros :as dm] [app.common.types.component :as ctk] [app.main.refs :as refs] - [app.main.ui.components.shape-icon :as si] [app.main.ui.components.shape-icon-refactor :as sir] [app.main.ui.components.tab-container :refer [tab-container tab-element]] - [app.main.ui.components.tabs-container :refer [tabs-container tabs-element]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.viewer.inspect.attributes :refer [attributes]] [app.main.ui.viewer.inspect.code :refer [code]] @@ -44,8 +41,7 @@ (mf/defc right-sidebar [{:keys [frame page objects file selected shapes page-id file-id share-id from on-change-section on-expand] :or {from :inspect}}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - section (mf/use-state :info #_:code) + (let [section (mf/use-state :info #_:code) objects (or objects (:objects page)) shapes (or shapes (resolve-shapes objects selected)) @@ -86,113 +82,60 @@ (when-not (seq shapes) (handle-change-tab :info)))) - (if new-css-system - [:aside {:class (stl/css-case :settings-bar-right true - :viewer-code (= from :inspect))} - (if (seq shapes) - [:div {:class (stl/css :tool-windows)} - [:div {:class (stl/css :shape-row)} - (if (> (count shapes) 1) - [:* - [:span {:class (stl/css :layers-icon)} i/layers-refactor] - [:span {:class (stl/css :layer-title)} (tr "inspect.tabs.code.selected.multiple" (count shapes))]] - [:* - [:span {:class (stl/css :shape-icon)} - [:& sir/element-icon-refactor {:shape first-shape :main-instance? main-instance?}]] - ;; Execution time translation strings: - ;; inspect.tabs.code.selected.circle - ;; inspect.tabs.code.selected.component - ;; inspect.tabs.code.selected.curve - ;; inspect.tabs.code.selected.frame - ;; inspect.tabs.code.selected.group - ;; inspect.tabs.code.selected.image - ;; inspect.tabs.code.selected.mask - ;; inspect.tabs.code.selected.path - ;; inspect.tabs.code.selected.rect - ;; inspect.tabs.code.selected.svg-raw - ;; inspect.tabs.code.selected.text - [:span {:class (stl/css :layer-title)} (:name first-shape)]])] - [:div {:class (stl/css :inspect-content)} - [:& tab-container {:on-change-tab handle-change-tab - :selected @section} - [:& tab-element {:id :info :title (tr "inspect.tabs.info")} - [:& attributes {:page-id page-id - :objects objects - :file-id file-id - :frame frame - :shapes shapes - :from from - :libraries libraries - :share-id share-id}]] + [:aside {:class (stl/css-case :settings-bar-right true + :viewer-code (= from :inspect))} + (if (seq shapes) + [:div {:class (stl/css :tool-windows)} + [:div {:class (stl/css :shape-row)} + (if (> (count shapes) 1) + [:* + [:span {:class (stl/css :layers-icon)} i/layers-refactor] + [:span {:class (stl/css :layer-title)} (tr "inspect.tabs.code.selected.multiple" (count shapes))]] + [:* + [:span {:class (stl/css :shape-icon)} + [:& sir/element-icon-refactor {:shape first-shape :main-instance? main-instance?}]] + ;; Execution time translation strings: + ;; inspect.tabs.code.selected.circle + ;; inspect.tabs.code.selected.component + ;; inspect.tabs.code.selected.curve + ;; inspect.tabs.code.selected.frame + ;; inspect.tabs.code.selected.group + ;; inspect.tabs.code.selected.image + ;; inspect.tabs.code.selected.mask + ;; inspect.tabs.code.selected.path + ;; inspect.tabs.code.selected.rect + ;; inspect.tabs.code.selected.svg-raw + ;; inspect.tabs.code.selected.text + [:span {:class (stl/css :layer-title)} (:name first-shape)]])] + [:div {:class (stl/css :inspect-content)} + [:& tab-container {:on-change-tab handle-change-tab + :selected @section} + [:& tab-element {:id :info :title (tr "inspect.tabs.info")} + [:& attributes {:page-id page-id + :objects objects + :file-id file-id + :frame frame + :shapes shapes + :from from + :libraries libraries + :share-id share-id}]] - [:& tab-element {:id :code :title (tr "inspect.tabs.code")} - [:& code {:frame frame - :shapes shapes - :on-expand handle-expand - :from from}]]]]] - [:div {:class (stl/css :empty)} - [:div {:class (stl/css :code-info)} - [:span {:class (stl/css :placeholder-icon)} - i/code-refactor] - [:span {:class (stl/css :placeholder-label)} - (tr "inspect.empty.select")]] - [:div {:class (stl/css :help-info)} - [:span {:class (stl/css :placeholder-icon)} - i/help-refactor] - [:span {:class (stl/css :placeholder-label)} - (tr "inspect.empty.help")]] - [:button {:class (stl/css :more-info-btn) - :on-click navigate-to-help} - (tr "inspect.empty.more-info")]])] - - - [:aside.settings-bar.settings-bar-right - [:div.settings-bar-inside - (if (seq shapes) - [:div.tool-window - [:div.tool-window-bar.big - (if (> (count shapes) 1) - [:* - [:span.tool-window-bar-icon i/layers] - [:span.tool-window-bar-title (tr "inspect.tabs.code.selected.multiple" (count shapes))]] - [:* - [:span.tool-window-bar-icon - [:& si/element-icon {:shape first-shape :main-instance? main-instance?}]] - ;; Execution time translation strings: - ;; inspect.tabs.code.selected.circle - ;; inspect.tabs.code.selected.component - ;; inspect.tabs.code.selected.curve - ;; inspect.tabs.code.selected.frame - ;; inspect.tabs.code.selected.group - ;; inspect.tabs.code.selected.image - ;; inspect.tabs.code.selected.mask - ;; inspect.tabs.code.selected.path - ;; inspect.tabs.code.selected.rect - ;; inspect.tabs.code.selected.svg-raw - ;; inspect.tabs.code.selected.text - [:span.tool-window-bar-title (:name first-shape)]])] - [:div.tool-window-content.inspect - [:& tabs-container {:on-change-tab handle-change-tab - :selected @section} - [:& tabs-element {:id :info :title (tr "inspect.tabs.info")} - [:& attributes {:page-id page-id - :objects objects - :file-id file-id - :frame frame - :shapes shapes - :from from - :libraries libraries - :share-id share-id}]] - - [:& tabs-element {:id :code :title (tr "inspect.tabs.code")} - [:& code {:frame frame - :shapes shapes - :on-expand handle-expand - :from from}]]]]] - [:div.empty - [:span.tool-window-bar-icon i/code] - [:div (tr "inspect.empty.select")] - [:span.tool-window-bar-icon i/help] - [:div (tr "inspect.empty.help")] - [:button.btn-primary.action {:on-click navigate-to-help} (tr "inspect.empty.more-info")]])]]) - )) + [:& tab-element {:id :code :title (tr "inspect.tabs.code")} + [:& code {:frame frame + :shapes shapes + :on-expand handle-expand + :from from}]]]]] + [:div {:class (stl/css :empty)} + [:div {:class (stl/css :code-info)} + [:span {:class (stl/css :placeholder-icon)} + i/code-refactor] + [:span {:class (stl/css :placeholder-label)} + (tr "inspect.empty.select")]] + [:div {:class (stl/css :help-info)} + [:span {:class (stl/css :placeholder-icon)} + i/help-refactor] + [:span {:class (stl/css :placeholder-label)} + (tr "inspect.empty.help")]] + [:button {:class (stl/css :more-info-btn) + :on-click navigate-to-help} + (tr "inspect.empty.more-info")]])])) diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss index f002dc630b..c5267edbfc 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss @@ -16,63 +16,73 @@ grid-area: right-sidebar; padding-top: $s-8; padding-left: $s-12; - .tool-windows { - height: 100%; - display: flex; - flex-direction: column; - .shape-row { - display: flex; - gap: $s-8; - align-items: center; - margin-bottom: $s-16; - .layers-icon, - .shape-icon { - @include flexCenter; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - .layer-title { - @include titleTipography; - color: $df-primary; - } - } - } - .empty { - display: flex; - flex-direction: column; - align-items: center; - gap: $s-40; - padding-top: $s-24; - .code-info, - .help-info { - @include flexColumn; - align-items: center; - justify-content: flex-start; - gap: $s-8; - .placeholder-icon { - @extend .empty-icon; - } - .placeholder-label { - @include titleTipography; - text-align: center; - width: $s-200; - color: $df-secondary; - } - } - .more-info-btn { - @extend .button-secondary; - @include tabTitleTipography; - height: $s-32; - padding: $s-8 $s-24; - } - } - .inspect-content { - flex: 1; - overflow: hidden; - } &.viewer-code { height: calc(100vh - $s-48); } } + +.tool-windows { + height: 100%; + display: flex; + flex-direction: column; +} + +.shape-row { + display: flex; + gap: $s-8; + align-items: center; + margin-bottom: $s-16; +} + +.layers-icon, +.shape-icon { + @include flexCenter; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } +} + +.layer-title { + @include titleTipography; + color: $df-primary; +} + +.empty { + display: flex; + flex-direction: column; + align-items: center; + gap: $s-40; + padding-top: $s-24; +} + +.code-info, +.help-info { + @include flexColumn; + align-items: center; + justify-content: flex-start; + gap: $s-8; +} + +.placeholder-icon { + @extend .empty-icon; +} + +.placeholder-label { + @include titleTipography; + text-align: center; + width: $s-200; + color: var(--empty-message-foreground-color); +} + +.more-info-btn { + @extend .button-secondary; + @include tabTitleTipography; + height: $s-32; + padding: $s-8 $s-24; +} + +.inspect-content { + flex: 1; + overflow: hidden; +} diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index 045d1d533c..ff447eb017 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -90,12 +90,12 @@ {:key (dm/str "workspace-" page-id) :ref node-ref} - [:section.workspace-viewport + [:section {:class (stl/css :workspace-viewport)} (when (dbg/enabled? :coordinates) [:& coordinates/coordinates {:colorpalette? colorpalette?}]) (when (dbg/enabled? :history-overlay) - [:div.history-debug-overlay + [:div {:class (stl/css :history-debug-overlay)} [:button {:on-click #(st/emit! dw/reinitialize-undo)} "CLEAR"] [:& history-toolbox]]) diff --git a/frontend/src/app/main/ui/workspace.scss b/frontend/src/app/main/ui/workspace.scss index 72633f95ce..410c831862 100644 --- a/frontend/src/app/main/ui/workspace.scss +++ b/frontend/src/app/main/ui/workspace.scss @@ -40,3 +40,25 @@ } } } + +.workspace-content { + grid-area: viewport; +} + +.history-debug-overlay { + bottom: 0; + max-height: $s-500; + width: $s-500; + overflow-y: auto; + position: absolute; + z-index: $z-index-modal; +} + +.workspace-viewport { + overflow: hidden; + transition: none; + display: grid; + grid-template-rows: $s-20 1fr; + grid-template-columns: $s-20 1fr; + flex: 1; +} diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs index 121ca11d98..35df73bdd8 100644 --- a/frontend/src/app/main/ui/workspace/comments.cljs +++ b/frontend/src/app/main/ui/workspace/comments.cljs @@ -28,8 +28,7 @@ (mf/defc sidebar-options [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - {cmode :mode cshow :show} (mf/deref refs/comments-local) + (let [{cmode :mode cshow :show} (mf/deref refs/comments-local) update-mode (mf/use-fn (fn [event] @@ -45,53 +44,30 @@ (let [mode (if (= :pending cshow) :all :pending)] (st/emit! (dcm/update-filters {:show mode})))))] - (if new-css-system - [:ul {:class (stl/css :comment-mode-dropdown)} - [:li {:class (stl/css-case :dropdown-item true - :selected (or (= :all cmode) (nil? cmode))) - :data-value "all" - :on-click update-mode} + [:ul {:class (stl/css :comment-mode-dropdown)} + [:li {:class (stl/css-case :dropdown-item true + :selected (or (= :all cmode) (nil? cmode))) + :data-value "all" + :on-click update-mode} - [:span {:class (stl/css :label)} (tr "labels.show-all-comments")] - [:span {:class (stl/css :icon)} i/tick-refactor]] - [:li {:class (stl/css-case :dropdown-item true - :selected (= :yours cmode)) - :data-value "yours" - :on-click update-mode} - [:span {:class (stl/css :label)} (tr "labels.show-your-comments")] - [:span {:class (stl/css :icon)} i/tick-refactor]] - [:li {:class (stl/css :separator)}] - [:li {:class (stl/css-case :dropdown-item true - :selected (= :pending cshow)) - :on-click update-show} - [:span {:class (stl/css :label)} (tr "labels.hide-resolved-comments")] - [:span {:class (stl/css :icon)} i/tick-refactor]]] - - - [:ul.dropdown.with-check - [:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode))) - :data-value "all" - :on-click update-mode} - [:span.icon i/tick] - [:span.label (tr "labels.show-all-comments")]] - - [:li {:class (dom/classnames :selected (= :yours cmode)) - :data-value "yours" - :on-click update-mode} - [:span.icon i/tick] - [:span.label (tr "labels.show-your-comments")]] - - [:hr] - - [:li {:class (dom/classnames :selected (= :pending cshow)) - :on-click update-show} - [:span.icon i/tick] - [:span.label (tr "labels.hide-resolved-comments")]]]))) + [:span {:class (stl/css :label)} (tr "labels.show-all-comments")] + [:span {:class (stl/css :icon)} i/tick-refactor]] + [:li {:class (stl/css-case :dropdown-item true + :selected (= :yours cmode)) + :data-value "yours" + :on-click update-mode} + [:span {:class (stl/css :label)} (tr "labels.show-your-comments")] + [:span {:class (stl/css :icon)} i/tick-refactor]] + [:li {:class (stl/css :separator)}] + [:li {:class (stl/css-case :dropdown-item true + :selected (= :pending cshow)) + :on-click update-show} + [:span {:class (stl/css :label)} (tr "labels.hide-resolved-comments")] + [:span {:class (stl/css :icon)} i/tick-refactor]]])) (mf/defc comments-sidebar [{:keys [users threads page-id from-viewer]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - threads-map (mf/deref refs/threads-ref) + (let [threads-map (mf/deref refs/threads-ref) profile (mf/deref refs/profile) users-refs (mf/deref refs/current-file-comments-users) users (or users users-refs) @@ -139,75 +115,41 @@ (dwcm/center-to-comment-thread thread) (-> (dcm/open-thread thread) (with-meta {::ev/origin "workspace"})))))))] - (if new-css-system - [:div {:class (stl/css :comments-section)} - [:div {:class (stl/css :comments-section-title)} - [:span (tr "labels.comments")] - [:button {:class (stl/css :close-button) - :on-click close-section} - i/close-refactor]] + [:div {:class (stl/css :comments-section)} + [:div {:class (stl/css :comments-section-title)} + [:span (tr "labels.comments")] + [:button {:class (stl/css :close-button) + :on-click close-section} + i/close-refactor]] - [:button {:class (stl/css :mode-dropdown-wrapper) - :on-click toggle-mode-selector} + [:button {:class (stl/css :mode-dropdown-wrapper) + :on-click toggle-mode-selector} - [:span {:class (stl/css :mode-label)} (case (:mode local) - (nil :all) (tr "labels.show-all-comments") - :yours (tr "labels.show-your-comments"))] - [:div {:class (stl/css :icon)} i/arrow-refactor]] + [:span {:class (stl/css :mode-label)} (case (:mode local) + (nil :all) (tr "labels.show-all-comments") + :yours (tr "labels.show-your-comments"))] + [:div {:class (stl/css :icon)} i/arrow-refactor]] - [:& dropdown {:show options? - :on-close #(reset! state* false)} - [:& sidebar-options {:local local}]] + [:& dropdown {:show options? + :on-close #(reset! state* false)} + [:& sidebar-options {:local local}]] - [:div {:class (stl/css :comments-section-content)} + [:div {:class (stl/css :comments-section-content)} - (if (seq tgroups) - [:div {:class (stl/css :thread-groups)} + (if (seq tgroups) + [:div {:class (stl/css :thread-groups)} + [:& cmt/comment-thread-group + {:group (first tgroups) + :on-thread-click on-thread-click + :users users}] + (for [tgroup (rest tgroups)] [:& cmt/comment-thread-group - {:group (first tgroups) + {:group tgroup :on-thread-click on-thread-click - :users users}] - (for [tgroup (rest tgroups)] - [:& cmt/comment-thread-group - {:group tgroup - :on-thread-click on-thread-click - :users users - :key (:page-id tgroup)}])] + :users users + :key (:page-id tgroup)}])] - [:div {:class (stl/css :thread-group-placeholder)} - [:span {:class (stl/css :placeholder-icon)} i/comments-refactor] - [:span {:class (stl/css :placeholder-label)} - (tr "labels.no-comments-available")]])]] - - - [:div.comments-section.comment-threads-section - [:div.workspace-comment-threads-sidebar-header - [:div.label (tr "labels.comments")] - [:div.options {:on-click toggle-mode-selector} - [:div.label (case (:mode local) - (nil :all) (tr "labels.all") - :yours (tr "labels.only-yours"))] - [:div.icon i/arrow-down]] - - [:& dropdown {:show options? - :on-close #(reset! state* false)} - [:& sidebar-options {:local local}]]] - - (if (seq tgroups) - [:div.thread-groups - [:& cmt/comment-thread-group - {:group (first tgroups) - :on-thread-click on-thread-click - :users users}] - (for [tgroup (rest tgroups)] - [:* - [:hr] - [:& cmt/comment-thread-group - {:group tgroup - :on-thread-click on-thread-click - :users users - :key (:page-id tgroup)}]])] - - [:div.thread-groups-placeholder - i/chat - (tr "labels.no-comments-available")])]))) + [:div {:class (stl/css :thread-group-placeholder)} + [:span {:class (stl/css :placeholder-icon)} i/comments-refactor] + [:span {:class (stl/css :placeholder-label)} + (tr "labels.no-comments-available")]])]])) diff --git a/frontend/src/app/main/ui/workspace/comments.scss b/frontend/src/app/main/ui/workspace/comments.scss index 7c45491e67..b742ea5890 100644 --- a/frontend/src/app/main/ui/workspace/comments.scss +++ b/frontend/src/app/main/ui/workspace/comments.scss @@ -133,6 +133,7 @@ @include titleTipography; text-align: center; width: $s-184; + color: var(--empty-message-foreground-color); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.cljs b/frontend/src/app/main/ui/workspace/sidebar/history.cljs index c4fb5650ea..4c292d905d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/history.cljs @@ -147,23 +147,6 @@ (t locale "workspace.undo.entry.unknown" value)))) (defn entry->icon [{:keys [type]}] - (case type - :page i/file-html - :shape i/layers - :rect i/box - :circle i/circle - :text i/text - :path i/curve - :frame i/artboard - :group i/folder - :color i/palette - :typography i/titlecase - :component i/component - :media i/image - :image i/image - i/layers)) - -(defn entry->icon-refactor [{:keys [type]}] (case type :page i/document-refactor :shape i/svg-refactor @@ -310,9 +293,10 @@ :on-pointer-enter #(reset! hover? true) :on-pointer-leave #(reset! hover? false) :on-click #(st/emit! (dwc/undo-to-index idx-entry))} + [:div {:class (stl/css :history-entry-summary)} [:div {:class (stl/css :history-entry-summary-icon)} - (entry->icon-refactor entry)] + (entry->icon entry)] [:div {:class (stl/css :history-entry-summary-text)} (entry->message locale entry)] (when (:detail entry) [:div {:class (stl/css-case :history-entry-summary-button true diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.scss b/frontend/src/app/main/ui/workspace/sidebar/history.scss index bafe0cff74..19d9af08d5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/history.scss @@ -60,7 +60,7 @@ .history-entry-empty-msg { @include titleTipography; - color: var(--title-foreground-secondary); + color: var(--empty-message-foreground-color); } .history-entries { diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs index dbdd285075..9a99b7dbfd 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs @@ -14,7 +14,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar]] - [app.main.ui.context :as ctx] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -23,40 +22,24 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - options (mf/deref refs/workspace-page-options) + (let [options (mf/deref refs/workspace-page-options) on-change (mf/use-fn #(st/emit! (dw/change-canvas-color %))) on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options))) on-close (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :options)))] - (if new-css-system - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} - [:& title-bar {:collapsable? false - :title (tr "workspace.options.canvas-background") - :class (stl/css :title-spacing-page)}]] - [:div {:class (stl/css :element-content)} - [:& color-row - {:disable-gradient true - :disable-opacity true - :disable-image true - :title (tr "workspace.options.canvas-background") - :color {:color (get options :background clr/canvas) - :opacity 1} - :on-change on-change - :on-open on-open - :on-close on-close}]]] - - [:div.element-set - [:div.element-set-title (tr "workspace.options.canvas-background")] - [:div.element-set-content - [:& color-row - {:disable-gradient true - :disable-opacity true - :disable-image true - :title (tr "workspace.options.canvas-background") - :color {:color (get options :background clr/canvas) - :opacity 1} - :on-change on-change - :on-open on-open - :on-close on-close}]]]))) + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? false + :title (tr "workspace.options.canvas-background") + :class (stl/css :title-spacing-page)}]] + [:div {:class (stl/css :element-content)} + [:& color-row + {:disable-gradient true + :disable-opacity true + :disable-image true + :title (tr "workspace.options.canvas-background") + :color {:color (get options :background clr/canvas) + :opacity 1} + :on-change on-change + :on-open on-open + :on-close on-close}]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index cad09c56ac..15be74946d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -15,7 +15,6 @@ [app.main.data.workspace.libraries :as dwl] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.color-bullet :as cb] [app.main.ui.components.color-bullet-new :as cbn] [app.main.ui.components.color-input :refer [color-input*]] [app.main.ui.components.numeric-input :refer [numeric-input*]] @@ -43,10 +42,9 @@ (mf/defc color-row [{:keys [index color disable-gradient disable-opacity disable-image on-change - on-reorder on-detach on-open on-close title on-remove + on-reorder on-detach on-open on-close on-remove disable-drag on-focus on-blur select-only select-on-focus]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - current-file-id (mf/use-ctx ctx/current-file-id) + (let [current-file-id (mf/use-ctx ctx/current-file-id) file-colors (mf/deref refs/workspace-file-colors) shared-libs (mf/deref refs/workspace-libraries) hover-detach (mf/use-state false) @@ -186,152 +184,87 @@ (when (not= prev-color color) (modal/update-props! :colorpicker {:data (parse-color color)}))) - (if new-css-system - [:div {:class (stl/css-case - :color-data true - :dnd-over-top (= (:over dprops) :top) - :dnd-over-bot (= (:over dprops) :bot)) - :ref dref} - [:span {:class (stl/css :color-info)} - [:span {:class (stl/css-case :color-name-wrapper true - :no-opacity (or disable-opacity - (not opacity?)) - :library-name-wrapper library-color? - :editing editing-text? - :gradient-name-wrapper gradient-color?)} - [:span {:class (stl/css :color-bullet-wrapper)} - [:& cbn/color-bullet {:color (cond-> color - (nil? color-name) (assoc - :id nil - :file-id nil)) - :mini? true - :on-click handle-click-color}]] - (cond - ;; Rendering a color with ID - library-color? - [:* - [:div {:class (stl/css :color-name) - :title (str color-name)} - - (str color-name)] - (when on-detach - [:button - {:class (stl/css :detach-btn) - :title (tr "settings.detach") - :on-pointer-enter #(reset! hover-detach true) - :on-pointer-leave #(reset! hover-detach false) - :on-click detach-value} - i/detach-refactor])] - - ;; Rendering a gradient - gradient-color? - [:* - [:div {:class (stl/css :color-name)} - (uc/gradient-type->string (get-in color [:gradient :type]))]] - - ;; Rendering an image - image-color? - [:* - [:div {:class (stl/css :color-name)} - (tr "media.image")]] - - ;; Rendering a plain color - :else - [:span {:class (stl/css :color-input-wrapper)} - [:> color-input* {:value (if multiple-colors? - "" - (-> color :color cc/remove-hash)) - :placeholder (tr "settings.multiple") - :className (stl/css :color-input) - :on-focus on-focus - :on-blur on-blur - :on-change handle-value-change}]])] - - (when opacity? - [:div {:class (stl/css :opacity-element-wrapper)} - [:span {:class (stl/css :icon-text)} - "%"] - [:> numeric-input* {:value (-> color :opacity opacity->string) - :className (stl/css :opacity-input) - :placeholder "--" - :select-on-focus select-on-focus - :on-focus on-focus - :on-blur on-blur - :on-change handle-opacity-change - :min 0 - :max 100}]])] - - (when (some? on-remove) - [:button {:class (stl/css :remove-btn) - :on-click on-remove} i/remove-refactor]) - (when select-only - [:button {:class (stl/css :select-btn) - :on-click handle-select} - i/move-refactor])] - - ;; OLD CSS - [:div.row-flex.color-data {:title title - :class (dom/classnames - :dnd-over-top (= (:over dprops) :top) - :dnd-over-bot (= (:over dprops) :bot)) - :ref dref} - [:& cb/color-bullet {:color (cond-> color - (nil? color-name) (assoc - :id nil - :file-id nil)) - :on-click handle-click-color}] - + [:div {:class (stl/css-case + :color-data true + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref} + [:span {:class (stl/css :color-info)} + [:span {:class (stl/css-case :color-name-wrapper true + :no-opacity (or disable-opacity + (not opacity?)) + :library-name-wrapper library-color? + :editing editing-text? + :gradient-name-wrapper gradient-color?)} + [:span {:class (stl/css :color-bullet-wrapper)} + [:& cbn/color-bullet {:color (cond-> color + (nil? color-name) (assoc + :id nil + :file-id nil)) + :mini? true + :on-click handle-click-color}]] (cond - ;; Rendering a color with ID + ;; Rendering a color with ID library-color? [:* - [:div.color-info - [:div.color-name (str color-name)]] + [:div {:class (stl/css :color-name) + :title (str color-name)} + + (str color-name)] (when on-detach - [:div.element-set-actions-button - {:on-pointer-enter #(reset! hover-detach true) + [:button + {:class (stl/css :detach-btn) + :title (tr "settings.detach") + :on-pointer-enter #(reset! hover-detach true) :on-pointer-leave #(reset! hover-detach false) :on-click detach-value} - (if @hover-detach i/unchain i/chain)])] + i/detach-refactor])] - ;; Rendering a gradient + ;; Rendering a gradient gradient-color? [:* - [:div.color-info - [:div.color-name (uc/gradient-type->string (get-in color [:gradient :type]))]] - (when select-only - [:div.element-set-actions-button {:on-click handle-select} - i/pointer-inner])] + [:div {:class (stl/css :color-name)} + (uc/gradient-type->string (get-in color [:gradient :type]))]] - ;; Rendering a plain color/opacity - :else + ;; Rendering an image + image-color? [:* - [:div.color-info - [:> color-input* {:value (if multiple-colors? - "" - (-> color :color cc/remove-hash)) - :placeholder (tr "settings.multiple") + [:div {:class (stl/css :color-name)} + (tr "media.image")]] + + ;; Rendering a plain color + :else + [:span {:class (stl/css :color-input-wrapper)} + [:> color-input* {:value (if multiple-colors? + "" + (-> color :color cc/remove-hash)) + :placeholder (tr "settings.multiple") + :className (stl/css :color-input) + :on-focus on-focus + :on-blur on-blur + :on-change handle-value-change}]])] + + (when opacity? + [:div {:class (stl/css :opacity-element-wrapper)} + [:span {:class (stl/css :icon-text)} + "%"] + [:> numeric-input* {:value (-> color :opacity opacity->string) + :className (stl/css :opacity-input) + :placeholder "--" + :select-on-focus select-on-focus :on-focus on-focus :on-blur on-blur - :on-change handle-value-change}]] + :on-change handle-opacity-change + :min 0 + :max 100}]])] - (when (and (not disable-opacity) - (not (:gradient color))) - [:div.input-element - {:class (dom/classnames :percentail (not= (:opacity color) :multiple))} - [:> numeric-input* {:value (-> color :opacity opacity->string) - :placeholder (tr "settings.multiple") - :select-on-focus select-on-focus - :on-focus on-focus - :on-blur on-blur - :on-change handle-opacity-change - :min 0 - :max 100}]]) - (when select-only - [:div.element-set-actions-button {:on-click handle-select} - i/pointer-inner])]) - (when (some? on-remove) - [:div.element-set-actions-button.remove {:on-click on-remove} i/minus])]) + (when (some? on-remove) + [:button {:class (stl/css :remove-btn) + :on-click on-remove} i/remove-refactor]) + (when select-only + [:button {:class (stl/css :select-btn) + :on-click handle-select} + i/move-refactor])] )) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss index 83f32b627a..5285303c5f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss @@ -8,155 +8,6 @@ .color-data { @include flexRow; - .color-info { - display: flex; - align-items: center; - gap: $s-2; - border-radius: $s-8; - background-color: var(--input-details-color); - height: $s-32; - width: 100%; - flex-grow: 1; - .color-name-wrapper { - @extend .input-element; - flex-grow: 1; - width: 100%; - border-radius: $br-8 0 0 $br-8; - padding: 0; - margin-right: 0; - gap: $s-4; - input { - padding: 0; - } - .color-bullet-wrapper { - height: $s-28; - padding: 0 $s-2 0 $s-8; - border-radius: $br-8 0 0 $br-8; - background-color: transparent; - &:hover { - background-color: transparent; - } - } - .color-name { - @include titleTipography; - display: flex; - align-items: center; - height: $s-28; - padding-left: $s-6; - border-radius: $br-8; - width: 100%; - flex-grow: 1; - color: var(--input-foreground-color-active); - } - .detach-btn { - @extend .button-tertiary; - height: $s-28; - width: $s-28; - border-radius: 0 $br-8 $br-8 0; - display: none; - svg { - @extend .button-icon; - } - } - .color-input-wrapper { - @include titleTipography; - display: flex; - align-items: center; - height: $s-28; - padding: 0 $s-0; - width: 100%; - margin: 0; - flex-grow: 1; - background-color: var(--input-background-color); - color: var(--input-foreground-color); - border-radius: $br-0; - } - &.no-opacity { - border-radius: $br-8; - .color-input-wrapper { - border-radius: $br-8; - } - } - &:hover { - background-color: var(--input-background-color-hover); - border: $s-1 solid var(--input-background-color-hover); - .color-bullet-wrapper, - .color-name, - .detach-btn, - .color-input-wrapper { - background-color: var(--input-background-color-hover); - } - .detach-btn { - display: flex; - svg { - stroke: var(--input-foreground-color-active); - } - } - &.editing { - background-color: var(--input-background-color-active); - .color-bullet-wrapper, - .color-name, - .detach-btn, - .color-input-wrapper { - background-color: var(--input-background-color-active); - } - } - } - &:focus, - &:focus-within { - background-color: var(--input-background-color-active); - } - - &.editing { - background-color: var(--input-background-color-active); - } - } - .gradient-name-wrapper { - border-radius: 0 $br-8 $br-8 0; - .color-name { - @include flexRow; - border-radius: 0 $br-8 $br-8 0; - } - } - .library-name-wrapper { - border-radius: $br-8; - } - .opacity-element-wrapper { - @extend .input-element; - width: $s-60; - border-radius: 0 $br-8 $br-8 0; - .opacity-input { - padding: 0; - border-radius: 0 $br-8 $br-8 0; - min-width: $s-28; - } - .icon-text { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - padding-top: $s-2; - } - } - - &:hover { - .detach-btn, - .select-btn { - background-color: transparent; - svg { - stroke: var(--input-foreground-color-active); - } - } - } - } - .remove-btn, - .select-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - } - } &.dnd-over-top { border-top: $s-1 solid var(--layer-row-foreground-color-drag); @@ -165,3 +16,155 @@ border-bottom: $s-1 solid var(--layer-row-foreground-color-drag); } } + +.color-info { + display: flex; + align-items: center; + gap: $s-2; + border-radius: $s-8; + background-color: var(--input-details-color); + height: $s-32; + width: 100%; + flex-grow: 1; + + .color-name-wrapper { + @extend .input-element; + flex-grow: 1; + width: 100%; + border-radius: $br-8 0 0 $br-8; + padding: 0; + margin-right: 0; + gap: $s-4; + input { + padding: 0; + } + .color-bullet-wrapper { + height: $s-28; + padding: 0 $s-2 0 $s-8; + border-radius: $br-8 0 0 $br-8; + background-color: transparent; + &:hover { + background-color: transparent; + } + } + .color-name { + @include titleTipography; + display: flex; + align-items: center; + height: $s-28; + padding-left: $s-6; + border-radius: $br-8; + width: 100%; + flex-grow: 1; + color: var(--input-foreground-color-active); + } + .detach-btn { + @extend .button-tertiary; + height: $s-28; + width: $s-28; + border-radius: 0 $br-8 $br-8 0; + display: none; + svg { + @extend .button-icon; + } + } + .color-input-wrapper { + @include titleTipography; + display: flex; + align-items: center; + height: $s-28; + padding: 0 $s-0; + width: 100%; + margin: 0; + flex-grow: 1; + background-color: var(--input-background-color); + color: var(--input-foreground-color); + border-radius: $br-0; + } + &.no-opacity { + border-radius: $br-8; + .color-input-wrapper { + border-radius: $br-8; + } + } + &:hover { + background-color: var(--input-background-color-hover); + border: $s-1 solid var(--input-background-color-hover); + .color-bullet-wrapper, + .color-name, + .detach-btn, + .color-input-wrapper { + background-color: var(--input-background-color-hover); + } + .detach-btn { + display: flex; + svg { + stroke: var(--input-foreground-color-active); + } + } + &.editing { + background-color: var(--input-background-color-active); + .color-bullet-wrapper, + .color-name, + .detach-btn, + .color-input-wrapper { + background-color: var(--input-background-color-active); + } + } + } + &:focus, + &:focus-within { + background-color: var(--input-background-color-active); + } + + &.editing { + background-color: var(--input-background-color-active); + } + } + .gradient-name-wrapper { + border-radius: 0 $br-8 $br-8 0; + .color-name { + @include flexRow; + border-radius: 0 $br-8 $br-8 0; + } + } + .library-name-wrapper { + border-radius: $br-8; + } + .opacity-element-wrapper { + @extend .input-element; + width: $s-60; + border-radius: 0 $br-8 $br-8 0; + .opacity-input { + padding: 0; + border-radius: 0 $br-8 $br-8 0; + min-width: $s-28; + } + .icon-text { + @include flexCenter; + height: $s-32; + margin-right: $s-4; + padding-top: $s-2; + } + } + + &:hover { + .detach-btn, + .select-btn { + background-color: transparent; + svg { + stroke: var(--input-foreground-color-active); + } + } + } +} + +.remove-btn, +.select-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs deleted file mode 100644 index f0aca9d255..0000000000 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs +++ /dev/null @@ -1,72 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) KALEIDOS INC - -(ns app.main.ui.workspace.sidebar.options.rows.input-row - (:require - [app.main.ui.components.editable-select :refer [editable-select]] - [app.main.ui.components.numeric-input :refer [numeric-input*]] - [app.main.ui.components.select :refer [select]] - [app.util.object :as obj] - [rumext.v2 :as mf])) - -(mf/defc input-row - [{:keys [label options value class min max on-change type placeholder default nillable on-focus select-on-focus]}] - [:div.row-flex.input-row - [:span.element-set-subtitle label] - [:div.input-element {:class class} - - (case type - :select - [:& select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :default-value value - :class "input-option" - :options options - :on-change on-change}] - - :editable-select - [:& editable-select {:value value - :class "input-option" - :options options - :type "number" - :min min - :max max - :placeholder placeholder - :on-change on-change}] - - :text - [:input {:value value - :class "input-text" - :on-change on-change} ] - - [:> numeric-input* - {:placeholder placeholder - :min min - :max max - :default default - :nillable nillable - :on-change on-change - :on-focus on-focus - :select-on-focus select-on-focus - :value (or value "")}])]]) - - -;; NOTE: (by niwinz) this is a new version of input-row, I didn't -;; touched the original one because it is used in many sites and I -;; don't have intention to refactor all the code right now. We should -;; consider to use the new one and once we have migrated all to the -;; new component, we can proceed to rename it and delete the old one. - -(mf/defc input-row-v2 - {::mf/wrap-props false} - [props] - (let [label (obj/get props "label") - class (obj/get props "class") - children (obj/get props "children")] - [:div.row-flex.input-row - [:span.element-set-subtitle label] - [:div.input-element {:class class} - children]])) - diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs index 2b661b1096..558e86b416 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs @@ -10,7 +10,6 @@ [app.common.data :as d] [app.common.types.shape.layout :as ctl] [app.main.refs :as refs] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu]] @@ -33,8 +32,7 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - shape (unchecked-get props "shape") + (let [shape (unchecked-get props "shape") shape-with-children (unchecked-get props "shape-with-children") shared-libs (unchecked-get props "shared-libs") objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v)))) @@ -69,8 +67,7 @@ [layout-item-ids layout-item-values] (get-attrs [shape] objects :layout-item)] - [:div {:class (stl/css-case new-css-system - :options true)} + [:div {:class (stl/css :options)} [:& layer-menu {:type type :ids layer-ids :values layer-values}] [:& measures-menu {:type type :ids measure-ids :values measure-values :shape shape}] [:& component-menu {:shapes [shape]}] ;;remove this in components-v2 diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 8309844a76..a562269aec 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -16,7 +16,6 @@ [app.common.types.shape.layout :as ctl] [app.main.data.workspace.texts :as dwt] [app.main.refs :as refs] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu]] [app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu]] @@ -268,8 +267,7 @@ {::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "shapes-with-children" "page-id" "file-id"]))] ::mf/wrap-props false} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - shapes (unchecked-get props "shapes") + (let [shapes (unchecked-get props "shapes") shapes-with-children (unchecked-get props "shapes-with-children") ;; remove children from bool shapes @@ -348,8 +346,7 @@ components (filter ctk/instance-head? shapes)] - [:div {:class (stl/css-case new-css-system - :options true)} + [:div {:class (stl/css :options)} (when-not (empty? layer-ids) [:& layer-menu {:type type :ids layer-ids :values layer-values}]) diff --git a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs index c3efb32784..04eeb79d1f 100644 --- a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs @@ -13,7 +13,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.context :as ctx] - [app.main.ui.icons :as i] [app.main.ui.workspace.viewport.grid-layout-editor :refer [grid-edition-actions]] [app.main.ui.workspace.viewport.path-actions :refer [path-actions]] [app.util.i18n :as i18n :refer [tr]] @@ -21,30 +20,19 @@ (mf/defc view-only-actions [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - handle-close-view-mode + (let [handle-close-view-mode (mf/use-callback (fn [] (st/emit! :interrupt (dw/set-options-mode :design) (dw/set-workspace-read-only false))))] - (if new-css-system - [:div {:class (stl/css :viewport-actions)} - [:div {:class (stl/css :viewport-actions-container)} - [:div {:class (stl/css :viewport-actions-title)} - [:& i18n/tr-html {:tag-name "span" - :label "workspace.top-bar.read-only"}]] - [:button {:class (stl/css :done-btn) - :on-click handle-close-view-mode} (tr "workspace.top-bar.read-only.done")]]] - - ;; OLD - [:div.viewport-actions - [:div.viewport-actions-container - [:div.viewport-actions-title - [:& i18n/tr-html {:tag-name "span" - :label "workspace.top-bar.read-only"}]] - [:button.btn-primary {:on-click handle-close-view-mode} (tr "workspace.top-bar.read-only.done")] - [:button.btn-icon-basic {:on-click handle-close-view-mode} i/close]]]))) + [:div {:class (stl/css :viewport-actions)} + [:div {:class (stl/css :viewport-actions-container)} + [:div {:class (stl/css :viewport-actions-title)} + [:& i18n/tr-html {:tag-name "span" + :label "workspace.top-bar.read-only"}]] + [:button {:class (stl/css :done-btn) + :on-click handle-close-view-mode} (tr "workspace.top-bar.read-only.done")]]])) (mf/defc top-bar {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 58fde157b7..ec646a9665 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.viewport.widgets + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -251,12 +252,14 @@ :width 100000 :height 24 :transform (vwu/text-transform flow-pos zoom)} - [:div.flow-badge {:class (dom/classnames :selected selected?)} - [:div.content {:on-pointer-down on-pointer-down + [:div {:class (stl/css-case :flow-badge true + :selected selected?)} + [:div {:class (stl/css :content) + :on-pointer-down on-pointer-down :on-double-click on-double-click :on-pointer-enter on-pointer-enter :on-pointer-leave on-pointer-leave} - i/play + i/play-refactor [:span (:name flow)]]]])) (mf/defc frame-flows diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.scss b/frontend/src/app/main/ui/workspace/viewport/widgets.scss new file mode 100644 index 0000000000..2fc2a81daf --- /dev/null +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.scss @@ -0,0 +1,64 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.flow-element { + display: flex; + align-items: center; + + .element-label { + } + + .flow-name { + cursor: pointer; + } + + & input.element-name { + background: transparent; + } +} + +.flow-badge { + cursor: pointer; + display: flex; + .content { + @include titleTipography; + display: flex; + align-items: center; + height: $s-24; + border-radius: $br-6; + background-color: var(--flow-tag-background-color); + svg { + @extend .button-icon; + height: $s-24; + width: $s-12; + stroke: var(--icon-foreground); + margin: 0 $s-8; + } + + span { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + margin-right: $s-8; + color: var(--flow-tag-foreground-color); + } + } + + &.selected .content, + &:hover .content { + background-color: var(--flow-tag-background-color-hover); + svg { + stroke: var(--flow-tag-foreground-color-hover); + } + + span { + color: var(--flow-tag-foreground-color-hover); + } + } +} From 3f151f16ced15d448b0507a24071c4ee7f7e9db3 Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 3 Jan 2024 13:23:06 +0100 Subject: [PATCH 23/35] :recycle: Remove new-css-system from modals --- frontend/src/app/main/ui/alert.cljs | 75 +- frontend/src/app/main/ui/alert.scss | 72 +- frontend/src/app/main/ui/auth.cljs | 112 +- frontend/src/app/main/ui/auth/login.cljs | 351 ++---- .../app/main/ui/auth/recovery_request.cljs | 75 +- frontend/src/app/main/ui/auth/register.cljs | 286 ++--- frontend/src/app/main/ui/comments.cljs | 584 +++------ frontend/src/app/main/ui/comments.scss | 160 +-- .../app/main/ui/components/file_uploader.cljs | 21 +- frontend/src/app/main/ui/confirm.cljs | 120 +- frontend/src/app/main/ui/confirm.scss | 107 +- .../app/main/ui/dashboard/change_owner.cljs | 98 +- .../app/main/ui/dashboard/change_owner.scss | 75 +- .../src/app/main/ui/dashboard/export.cljs | 229 ++-- .../src/app/main/ui/dashboard/export.scss | 101 +- .../src/app/main/ui/dashboard/import.cljs | 312 ++--- .../src/app/main/ui/dashboard/import.scss | 122 +- frontend/src/app/main/ui/dashboard/team.cljs | 1122 +++++------------ .../src/app/main/ui/dashboard/team_form.cljs | 86 +- frontend/src/app/main/ui/delete_shared.cljs | 124 +- frontend/src/app/main/ui/delete_shared.scss | 86 +- frontend/src/app/main/ui/messages.cljs | 122 +- frontend/src/app/main/ui/messages.scss | 9 - frontend/src/app/main/ui/modal.cljs | 5 +- frontend/src/app/main/ui/onboarding.cljs | 255 ++-- .../app/main/ui/onboarding/newsletter.cljs | 117 +- .../app/main/ui/onboarding/team_choice.cljs | 305 ++--- .../app/main/ui/settings/access_tokens.cljs | 356 ++---- .../app/main/ui/settings/access_tokens.scss | 150 +-- .../app/main/ui/settings/change_email.cljs | 108 +- .../app/main/ui/settings/change_email.scss | 80 +- .../app/main/ui/settings/delete_account.cljs | 68 +- .../app/main/ui/settings/delete_account.scss | 86 +- frontend/src/app/main/ui/viewer/login.cljs | 156 +-- .../src/app/main/ui/viewer/share_link.cljs | 373 ++---- .../app/main/ui/workspace/left_header.scss | 3 +- .../src/app/main/ui/workspace/libraries.scss | 3 + frontend/src/app/main/ui/workspace/nudge.cljs | 67 +- frontend/src/app/main/ui/workspace/nudge.scss | 56 +- .../src/app/main/ui/workspace/sidebar.cljs | 103 +- .../sidebar/assets/file_library.cljs | 4 +- 41 files changed, 2359 insertions(+), 4385 deletions(-) diff --git a/frontend/src/app/main/ui/alert.cljs b/frontend/src/app/main/ui/alert.cljs index 7511c390b1..8c7ee4b020 100644 --- a/frontend/src/app/main/ui/alert.cljs +++ b/frontend/src/app/main/ui/alert.cljs @@ -9,7 +9,6 @@ (:require [app.main.data.modal :as modal] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -27,8 +26,8 @@ hint accept-label accept-style] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-accept (or on-accept identity) + + (let [on-accept (or on-accept identity) message (or message (tr "ds.alert-title")) accept-label (or accept-label (tr "ds.alert-ok")) accept-style (or accept-style :danger) @@ -50,54 +49,26 @@ (on-accept props)))] (->> (events/listen js/document "keydown" on-keydown) (partial events/unlistenByKey)))) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} title] - [:button {:class (stl/css :modal-close-btn) - :on-click accept-fn} i/close-refactor]] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} title] + [:button {:class (stl/css :modal-close-btn) + :on-click accept-fn} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - (when (and (string? message) (not= message "")) - [:h3 {:class (stl/css :modal-msg)} message]) - (when (and (string? scd-message) (not= scd-message "")) - [:h3 {:class (stl/css :modal-scd-msg)} scd-message]) - (when (string? hint) - [:p {:class (stl/css :modal-hint)} hint])] + [:div {:class (stl/css :modal-content)} + (when (and (string? message) (not= message "")) + [:h3 {:class (stl/css :modal-msg)} message]) + (when (and (string? scd-message) (not= scd-message "")) + [:h3 {:class (stl/css :modal-scd-msg)} scd-message]) + (when (string? hint) + [:p {:class (stl/css :modal-hint)} hint])] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:input {:class (stl/css-case :accept-btn true - :danger (= accept-style :danger) - :primary (= accept-style :primary)) - :type "button" - :value accept-label - :on-click accept-fn}]]]]] - - - [:div.modal-overlay - [:div.modal-container.alert-dialog - [:div.modal-header - [:div.modal-header-title - [:h2 title]] - [:div.modal-close-button - {:on-click accept-fn} i/close]] - - [:div.modal-content - (when (and (string? message) (not= message "")) - [:h3 message]) - (when (and (string? scd-message) (not= scd-message "")) - [:h3 scd-message]) - (when (string? hint) - [:p hint])] - - [:div.modal-footer - [:div.action-buttons - [:input.accept-button - {:class (dom/classnames - :danger (= accept-style :danger) - :primary (= accept-style :primary)) - :type "button" - :value accept-label - :on-click accept-fn}]]]]]))) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:input {:class (stl/css-case :accept-btn true + :danger (= accept-style :danger) + :primary (= accept-style :primary)) + :type "button" + :value accept-label + :on-click accept-fn}]]]]])) diff --git a/frontend/src/app/main/ui/alert.scss b/frontend/src/app/main/ui/alert.scss index 066381d194..2d4a8b1d78 100644 --- a/frontend/src/app/main/ui/alert.scss +++ b/frontend/src/app/main/ui/alert.scss @@ -11,39 +11,45 @@ &.transparent { background-color: transparent; } - .modal-container { - @extend .modal-container-base; - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } - .modal-content { - @include titleTipography; - margin-bottom: $s-24; - .modal-hint { - @include titleTipography; - } - } - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-btn { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } - } +} +.modal-container { + @extend .modal-container-base; +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + margin-bottom: $s-24; +} + +.modal-hint { + @include titleTipography; +} + +.action-buttons { + @extend .modal-action-btns; +} + +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; } } diff --git a/frontend/src/app/main/ui/auth.cljs b/frontend/src/app/main/ui/auth.cljs index 37f5398722..fe84732526 100644 --- a/frontend/src/app/main/ui/auth.cljs +++ b/frontend/src/app/main/ui/auth.cljs @@ -12,7 +12,6 @@ [app.main.ui.auth.recovery :refer [recovery-page]] [app.main.ui.auth.recovery-request :refer [recovery-request-page]] [app.main.ui.auth.register :refer [register-page register-success-page register-validate-page]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -20,102 +19,57 @@ (mf/defc terms-login [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - show-all? (and cf/terms-of-service-uri cf/privacy-policy-uri) + (let [show-all? (and cf/terms-of-service-uri cf/privacy-policy-uri) show-terms? (some? cf/terms-of-service-uri) show-privacy? (some? cf/privacy-policy-uri)] - (if new-css-system - (when show-all? - [:div {:class (stl/css :terms-login)} - (when show-terms? - [:a {:href cf/terms-of-service-uri :target "_blank"} (tr "auth.terms-of-service")]) + (when show-all? + [:div {:class (stl/css :terms-login)} + (when show-terms? + [:a {:href cf/terms-of-service-uri :target "_blank"} (tr "auth.terms-of-service")]) - (when show-all? - [:span (tr "labels.and")]) + (when show-all? + [:span (tr "labels.and")]) - (when show-privacy? - [:a {:href cf/privacy-policy-uri :target "_blank"} (tr "auth.privacy-policy")])]) - - (when show-all? - [:div.terms-login - (when show-terms? - [:a {:href cf/terms-of-service-uri :target "_blank"} (tr "auth.terms-of-service")]) - - (when show-all? - [:span (tr "labels.and")]) - - (when show-privacy? - [:a {:href cf/privacy-policy-uri :target "_blank"} (tr "auth.privacy-policy")])])))) + (when show-privacy? + [:a {:href cf/privacy-policy-uri :target "_blank"} (tr "auth.privacy-policy")])]))) (mf/defc auth [{:keys [route] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - section (get-in route [:data :name]) + (let [section (get-in route [:data :name]) params (:query-params route) show-illustration? (contains? cf/flags :login-illustration)] (mf/use-effect #(dom/set-html-title (tr "title.default"))) - (if new-css-system - [:main {:class (stl/css-case :auth-section true - :no-illustration (not show-illustration?))} - (when show-illustration? - [:div {:class (stl/css :login-illustration)} - i/login-illustration]) + [:main {:class (stl/css-case :auth-section true + :no-illustration (not show-illustration?))} + (when show-illustration? + [:div {:class (stl/css :login-illustration)} + i/login-illustration]) - [:section {:class (stl/css :auth-content)} - [:* - [:a {:href "#/" :class (stl/css :logo-btn)}i/logo] - (case section - :auth-register - [:& register-page {:params params}] + [:section {:class (stl/css :auth-content)} + [:* + [:a {:href "#/" :class (stl/css :logo-btn)} i/logo] + (case section + :auth-register + [:& register-page {:params params}] - :auth-register-validate - [:& register-validate-page {:params params}] + :auth-register-validate + [:& register-validate-page {:params params}] - :auth-register-success - [:& register-success-page {:params params}] + :auth-register-success + [:& register-success-page {:params params}] - :auth-login - [:& login-page {:params params}] + :auth-login + [:& login-page {:params params}] - :auth-recovery-request - [:& recovery-request-page] + :auth-recovery-request + [:& recovery-request-page] - :auth-recovery - [:& recovery-page {:params params}])] + :auth-recovery + [:& recovery-page {:params params}])] - (when (contains? #{:auth-login :auth-register} section) - [:& terms-login])]] - - ;; OLD - [:main.auth - [:section.auth-sidebar - [:a.logo {:href "#/"} - [:span {:aria-hidden true} i/logo] - [:span.hidden-name "Home"]] - [:span.tagline (tr "auth.sidebar-tagline")]] - - [:section.auth-content - (case section - :auth-register - [:& register-page {:params params}] - - :auth-register-validate - [:& register-validate-page {:params params}] - - :auth-register-success - [:& register-success-page {:params params}] - - :auth-login - [:& login-page {:params params}] - - :auth-recovery-request - [:& recovery-request-page] - - :auth-recovery - [:& recovery-page {:params params}]) - - [:& terms-login {}]]]))) + (when (contains? #{:auth-login :auth-register} section) + [:& terms-login])]])) diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 249ed8e99e..abf47e0404 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -18,7 +18,6 @@ [app.main.ui.components.button-link :as bl] [app.main.ui.components.forms :as fm] [app.main.ui.components.link :as lk] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.dom :as dom] @@ -94,8 +93,7 @@ (mf/defc login-form [{:keys [params on-success-callback origin] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - initial (mf/use-memo (mf/deps params) (constantly params)) + (let [initial (mf/use-memo (mf/deps params) (constantly params)) error (mf/use-state false) form (fm/use-form :spec ::login-form :validators [handle-error-messages] @@ -157,156 +155,86 @@ (mf/use-fn #(st/emit! (rt/nav :auth-recovery-request)))] - (if new-css-system - [:* - (when-let [message @error] - [:& msgs/inline-banner - {:type :warning - :content message - :on-close #(reset! error nil) - :data-test "login-banner" - :role "alert"}]) + [:* + (when-let [message @error] + [:& msgs/inline-banner + {:type :warning + :content message + :on-close #(reset! error nil) + :data-test "login-banner" + :role "alert"}]) - [:& fm/form {:on-submit on-submit :form form} - [:div {:class (stl/css :fields-row)} - [:& fm/input - {:name :email - :type "email" - :label (tr "auth.email") - :class (stl/css :form-field)}]] + [:& fm/form {:on-submit on-submit :form form} + [:div {:class (stl/css :fields-row)} + [:& fm/input + {:name :email + :type "email" + :label (tr "auth.email") + :class (stl/css :form-field)}]] - [:div {:class (stl/css :fields-row)} - [:& fm/input - {:type "password" - :name :password - :label (tr "auth.password") - :class (stl/css :form-field)}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input + {:type "password" + :name :password + :label (tr "auth.password") + :class (stl/css :form-field)}]] - (when (and (not= origin :viewer) - (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password))) - [:div {:class (stl/css :fields-row :forgot-password)} - [:& lk/link {:action on-recovery-request - :data-test "forgot-password"} - (tr "auth.forgot-password")]]) + (when (and (not= origin :viewer) + (or (contains? cf/flags :login) + (contains? cf/flags :login-with-password))) + [:div {:class (stl/css :fields-row :forgot-password)} + [:& lk/link {:action on-recovery-request + :data-test "forgot-password"} + (tr "auth.forgot-password")]]) - [:div {:class (stl/css :buttons-stack)} - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password)) - [:> fm/submit-button* - {:label (tr "auth.login-submit") - :data-test "login-submit" - :class (stl/css :login-button)}]) + [:div {:class (stl/css :buttons-stack)} + (when (or (contains? cf/flags :login) + (contains? cf/flags :login-with-password)) + [:> fm/submit-button* + {:label (tr "auth.login-submit") + :data-test "login-submit" + :class (stl/css :login-button)}]) - (when (contains? cf/flags :login-with-ldap) - [:> fm/submit-button* - {:label (tr "auth.login-with-ldap-submit") - :on-click on-submit-ldap}])]]] - - - ;; OLD - [:* - (when-let [message @error] - [:& msgs/inline-banner - {:type :warning - :content message - :on-close #(reset! error nil) - :data-test "login-banner" - :role "alert"}]) - - [:& fm/form {:on-submit on-submit :form form} - [:div.fields-row - [:& fm/input - {:name :email - :type "email" - :help-icon i/at - :label (tr "auth.email") - :class (stl/css :form-field)}]] - - [:div.fields-row - [:& fm/input - {:type "password" - :name :password - :help-icon i/eye - :label (tr "auth.password") - :class (stl/css :form-field)}]] - - [:div.buttons-stack - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password)) - [:> fm/submit-button* - {:label (tr "auth.login-submit") - :data-test "login-submit"}]) - - (when (contains? cf/flags :login-with-ldap) - [:> fm/submit-button* - {:label (tr "auth.login-with-ldap-submit") - :on-click on-submit-ldap}])]]]))) + (when (contains? cf/flags :login-with-ldap) + [:> fm/submit-button* + {:label (tr "auth.login-with-ldap-submit") + :on-click on-submit-ldap}])]]])) (mf/defc login-buttons [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - login-with-google (mf/use-fn (mf/deps params) #(login-with-oidc % :google params)) + (let [login-with-google (mf/use-fn (mf/deps params) #(login-with-oidc % :google params)) login-with-github (mf/use-fn (mf/deps params) #(login-with-oidc % :github params)) login-with-gitlab (mf/use-fn (mf/deps params) #(login-with-oidc % :gitlab params)) login-with-oidc (mf/use-fn (mf/deps params) #(login-with-oidc % :oidc params))] - (if new-css-system - [:div {:class (stl/css :auth-buttons)} - (when (contains? cf/flags :login-with-google) - [:& bl/button-link {:on-click login-with-google - :icon i/brand-google - :label (tr "auth.login-with-google-submit") - :class (stl/css :login-btn :btn-google-auth)}]) + [:div {:class (stl/css :auth-buttons)} + (when (contains? cf/flags :login-with-google) + [:& bl/button-link {:on-click login-with-google + :icon i/brand-google + :label (tr "auth.login-with-google-submit") + :class (stl/css :login-btn :btn-google-auth)}]) - (when (contains? cf/flags :login-with-github) - [:& bl/button-link {:on-click login-with-github - :icon i/brand-github - :label (tr "auth.login-with-github-submit") - :class (stl/css :login-btn :btn-github-auth)}]) + (when (contains? cf/flags :login-with-github) + [:& bl/button-link {:on-click login-with-github + :icon i/brand-github + :label (tr "auth.login-with-github-submit") + :class (stl/css :login-btn :btn-github-auth)}]) - (when (contains? cf/flags :login-with-gitlab) - [:& bl/button-link {:on-click login-with-gitlab - :icon i/brand-gitlab - :label (tr "auth.login-with-gitlab-submit") - :class (stl/css :login-btn :btn-gitlab-auth)}]) + (when (contains? cf/flags :login-with-gitlab) + [:& bl/button-link {:on-click login-with-gitlab + :icon i/brand-gitlab + :label (tr "auth.login-with-gitlab-submit") + :class (stl/css :login-btn :btn-gitlab-auth)}]) - (when (contains? cf/flags :login-with-oidc) - [:& bl/button-link {:on-click login-with-oidc - :icon i/brand-openid - :label (tr "auth.login-with-oidc-submit") - :class (stl/css :login-btn :btn-oidc-auth)}])] - - [:div.auth-buttons - (when (contains? cf/flags :login-with-google) - [:& bl/button-link {:on-click login-with-google - :icon i/brand-google - :label (tr "auth.login-with-google-submit") - :class "btn-google-auth"}]) - - (when (contains? cf/flags :login-with-github) - [:& bl/button-link {:on-click login-with-github - :icon i/brand-github - :label (tr "auth.login-with-github-submit") - :class "btn-github-auth"}]) - - (when (contains? cf/flags :login-with-gitlab) - [:& bl/button-link {:on-click login-with-gitlab - :icon i/brand-gitlab - :label (tr "auth.login-with-gitlab-submit") - :class "btn-gitlab-auth"}]) - - (when (contains? cf/flags :login-with-oidc) - [:& bl/button-link {:on-click login-with-oidc - :icon i/brand-openid - :label (tr "auth.login-with-oidc-submit") - :class "btn-github-auth"}])]))) + (when (contains? cf/flags :login-with-oidc) + [:& bl/button-link {:on-click login-with-oidc + :icon i/brand-openid + :label (tr "auth.login-with-oidc-submit") + :class (stl/css :login-btn :btn-oidc-auth)}])])) (mf/defc login-button-oidc [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - login-oidc + (let [login-oidc (mf/use-fn (mf/deps params) (fn [event] @@ -317,69 +245,33 @@ (fn [event] (when (k/enter? event) (login-oidc event))))] - (if new-css-system - (when (contains? cf/flags :login-with-oidc) - [:div {:class (stl/css :link-entry :link-oidc)} - [:a {:tab-index "0" - :on-key-down handle-key-down - :on-click login-oidc} - (tr "auth.login-with-oidc-submit")]]) - - ;; OLD - (when (contains? cf/flags :login-with-oidc) - [:div.link-entry.link-oidc - [:a {:tab-index "0" - :on-key-down handle-key-down - :on-click login-oidc} - (tr "auth.login-with-oidc-submit")]])))) + (when (contains? cf/flags :login-with-oidc) + [:div {:class (stl/css :link-entry :link-oidc)} + [:a {:tab-index "0" + :on-key-down handle-key-down + :on-click login-oidc} + (tr "auth.login-with-oidc-submit")]]))) (mf/defc login-methods [{:keys [params on-success-callback origin] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:* - (when show-alt-login-buttons? - [:* - [:& login-buttons {:params params}] + [:* + (when show-alt-login-buttons? + [:* + [:& login-buttons {:params params}] - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password) - (contains? cf/flags :login-with-ldap)) - [:hr {:class (stl/css :separator)}])]) + (when (or (contains? cf/flags :login) + (contains? cf/flags :login-with-password) + (contains? cf/flags :login-with-ldap)) + [:hr {:class (stl/css :separator)}])]) - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password) - (contains? cf/flags :login-with-ldap)) - [:& login-form {:params params :on-success-callback on-success-callback :origin origin}])] - - ;; OLD - [:* - (when show-alt-login-buttons? - [:* - [:span.separator - [:span.line] - [:span.text (tr "labels.continue-with")] - [:span.line]] - - [:& login-buttons {:params params}] - - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password) - (contains? cf/flags :login-with-ldap)) - [:span.separator - [:span.line] - [:span.text (tr "labels.or")] - [:span.line]])]) - - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password) - (contains? cf/flags :login-with-ldap)) - [:& login-form {:params params :on-success-callback on-success-callback}])]))) + (when (or (contains? cf/flags :login) + (contains? cf/flags :login-with-password) + (contains? cf/flags :login-with-ldap)) + [:& login-form {:params params :on-success-callback on-success-callback :origin origin}])]) (mf/defc login-page [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - go-register + (let [go-register (mf/use-fn #(st/emit! (rt/nav :auth-register {} params))) @@ -391,64 +283,33 @@ (mf/use-fn #(st/emit! (du/create-demo-profile)))] - (if new-css-system - [:div {:class (stl/css :auth-form)} - [:h1 {:class (stl/css :auth-title) - :data-test "login-title"} (tr "auth.login-title")] + [:div {:class (stl/css :auth-form)} + [:h1 {:class (stl/css :auth-title) + :data-test "login-title"} (tr "auth.login-title")] - [:hr {:class (stl/css :separator)}] + [:hr {:class (stl/css :separator)}] - [:& login-methods {:params params}] + [:& login-methods {:params params}] - [:div {:class (stl/css :links)} - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password)) - [:div {:class (stl/css :link-entry :register)} - [:& lk/link {:action on-pass-recovery - :data-test "forgot-password"} - (tr "auth.forgot-password")]]) + [:div {:class (stl/css :links)} + (when (or (contains? cf/flags :login) + (contains? cf/flags :login-with-password)) + [:div {:class (stl/css :link-entry :register)} + [:& lk/link {:action on-pass-recovery + :data-test "forgot-password"} + (tr "auth.forgot-password")]]) - (when (contains? cf/flags :registration) - [:div {:class (stl/css :link-entry :register)} - [:span (tr "auth.register") " "] - [:& lk/link {:action go-register - :data-test "register-submit"} - (tr "auth.register-submit")]])] + (when (contains? cf/flags :registration) + [:div {:class (stl/css :link-entry :register)} + [:span (tr "auth.register") " "] + [:& lk/link {:action go-register + :data-test "register-submit"} + (tr "auth.register-submit")]])] - (when (contains? cf/flags :demo-users) - [:div {:class (stl/css :link-entry :demo-account)} - [:span (tr "auth.create-demo-profile") " "] - [:& lk/link {:action on-create-demo-profile - :data-test "demo-account-link"} - (tr "auth.create-demo-account")]])] - - ;; OLD - [:div.generic-form.login-form - [:div.form-container - [:h1 {:data-test "login-title"} (tr "auth.login-title")] - - [:& login-methods {:params params}] - - [:div.links - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password)) - [:div.link-entry - [:& lk/link {:action on-pass-recovery - :data-test "forgot-password"} - (tr "auth.forgot-password")]]) - - (when (contains? cf/flags :registration) - [:div.link-entry - [:span (tr "auth.register") " "] - [:& lk/link {:action go-register - :data-test "register-submit"} - (tr "auth.register-submit")]])] - - (when (contains? cf/flags :demo-users) - [:div.links.demo - [:div.link-entry - [:span (tr "auth.create-demo-profile") " "] - [:& lk/link {:action on-create-demo-profile - :data-test "demo-account-link"} - (tr "auth.create-demo-account")]]])]]))) + (when (contains? cf/flags :demo-users) + [:div {:class (stl/css :link-entry :demo-account)} + [:span (tr "auth.create-demo-profile") " "] + [:& lk/link {:action on-create-demo-profile + :data-test "demo-account-link"} + (tr "auth.create-demo-account")]])])) diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs index f9138025ff..d45720ea11 100644 --- a/frontend/src/app/main/ui/auth/recovery_request.cljs +++ b/frontend/src/app/main/ui/auth/recovery_request.cljs @@ -14,8 +14,6 @@ [app.main.store :as st] [app.main.ui.components.forms :as fm] [app.main.ui.components.link :as lk] - [app.main.ui.context :as ctx] - [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [beicon.v2.core :as rx] @@ -34,8 +32,7 @@ (mf/defc recovery-form [{:keys [on-success-callback] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - form (fm/use-form :spec ::recovery-request-form + (let [form (fm/use-form :spec ::recovery-request-form :validators [handle-error-messages] :initial {}) submitted (mf/use-state false) @@ -77,62 +74,34 @@ (reset! form nil) (st/emit! (du/request-profile-recovery params)))))] - (if new-css-system - [:& fm/form {:on-submit on-submit - :form form} - [:div {:class (stl/css :fields-row)} - [:& fm/input {:name :email - :label (tr "auth.email") - :type "text" - :class (stl/css :form-field)}]] + [:& fm/form {:on-submit on-submit + :form form} + [:div {:class (stl/css :fields-row)} + [:& fm/input {:name :email + :label (tr "auth.email") + :type "text" + :class (stl/css :form-field)}]] - [:> fm/submit-button* - {:label (tr "auth.recovery-request-submit") - :data-test "recovery-resquest-submit" - :class (stl/css :recover-btn)}]] - - ;; OLD - [:& fm/form {:on-submit on-submit - :form form} - [:div.fields-row - [:& fm/input {:name :email - :label (tr "auth.email") - :help-icon i/at - :type "text"}]] - - [:> fm/submit-button* - {:label (tr "auth.recovery-request-submit") - :data-test "recovery-resquest-submit"}]]))) + [:> fm/submit-button* + {:label (tr "auth.recovery-request-submit") + :data-test "recovery-resquest-submit" + :class (stl/css :recover-btn)}]])) ;; --- Recovery Request Page (mf/defc recovery-request-page [{:keys [params on-success-callback go-back-callback] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - default-go-back #(st/emit! (rt/nav :auth-login)) + (let [default-go-back #(st/emit! (rt/nav :auth-login)) go-back (or go-back-callback default-go-back)] - (if new-css-system - [:div {:class (stl/css :auth-form)} - [:h1 {:class (stl/css :auth-title)} (tr "auth.recovery-request-title")] - [:div {:class (stl/css :auth-subtitle)} (tr "auth.recovery-request-subtitle")] - [:hr {:class (stl/css :separator)}] + [:div {:class (stl/css :auth-form)} + [:h1 {:class (stl/css :auth-title)} (tr "auth.recovery-request-title")] + [:div {:class (stl/css :auth-subtitle)} (tr "auth.recovery-request-subtitle")] + [:hr {:class (stl/css :separator)}] - [:& recovery-form {:params params :on-success-callback on-success-callback}] + [:& recovery-form {:params params :on-success-callback on-success-callback}] - [:div {:class (stl/css :link-entry)} - [:& lk/link {:action go-back - :data-test "go-back-link"} - (tr "labels.go-back")]]] - - ;; old - [:section.generic-form - [:div.form-container - [:h1 (tr "auth.recovery-request-title")] - [:div.subtitle (tr "auth.recovery-request-subtitle")] - [:& recovery-form {:params params :on-success-callback on-success-callback}] - [:div.links - [:div.link-entry - [:& lk/link {:action go-back - :data-test "go-back-link"} - (tr "labels.go-back")]]]]]))) + [:div {:class (stl/css :link-entry)} + [:& lk/link {:action go-back + :data-test "go-back-link"} + (tr "labels.go-back")]]])) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index 432c852ae4..573c989209 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -17,7 +17,6 @@ [app.main.ui.auth.login :as login] [app.main.ui.components.forms :as fm] [app.main.ui.components.link :as lk] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.i18n :refer [tr tr-html]] @@ -88,8 +87,7 @@ (mf/defc register-form [{:keys [params on-success-callback] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - initial (mf/use-memo (mf/deps params) (constantly params)) + (let [initial (mf/use-memo (mf/deps params) (constantly params)) form (fm/use-form :spec ::register-form :validators [validate (fm/validate-not-empty :password (tr "auth.password-not-empty"))] @@ -114,133 +112,64 @@ (partial handle-prepare-register-error form))))))] - (if new-css-system - [:& fm/form {:on-submit on-submit :form form} - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "email" - :name :email - :label (tr "auth.email") - :data-test "email-input" - :show-success? true - :class (stl/css :form-field)}]] - [:div {:class (stl/css :fields-row)} - [:& fm/input {:name :password - :hint (tr "auth.password-length-hint") - :label (tr "auth.password") - :show-success? true - :type "password" - :class (stl/css :form-field)}]] + [:& fm/form {:on-submit on-submit :form form} + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "email" + :name :email + :label (tr "auth.email") + :data-test "email-input" + :show-success? true + :class (stl/css :form-field)}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input {:name :password + :hint (tr "auth.password-length-hint") + :label (tr "auth.password") + :show-success? true + :type "password" + :class (stl/css :form-field)}]] - [:> fm/submit-button* - {:label (tr "auth.register-submit") - :disabled @submitted? - :data-test "register-form-submit" - :class (stl/css :register-btn)}]] - - ;; OLD - [:& fm/form {:on-submit on-submit - :form form} - [:div.fields-row - [:& fm/input {:type "email" - :name :email - :help-icon i/at - :label (tr "auth.email") - :data-test "email-input"}]] - [:div.fields-row - [:& fm/input {:name :password - :hint (tr "auth.password-length-hint") - :label (tr "auth.password") - :type "password"}]] - - [:> fm/submit-button* - {:label (tr "auth.register-submit") - :disabled @submitted? - :data-test "register-form-submit"}]]))) + [:> fm/submit-button* + {:label (tr "auth.register-submit") + :disabled @submitted? + :data-test "register-form-submit" + :class (stl/css :register-btn)}]])) (mf/defc register-methods [{:keys [params on-success-callback] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:* - (when login/show-alt-login-buttons? - [:* - [:hr {:class (stl/css :separator)}] - [:& login/login-buttons {:params params}]]) - [:hr {:class (stl/css :separator)}] - [:& register-form {:params params :on-success-callback on-success-callback}]] - - ;; OLD - [:* - (when login/show-alt-login-buttons? - [:* - [:span.separator - [:span.line] - [:span.text (tr "labels.continue-with")] - [:span.line]] - - [:& login/login-buttons {:params params}] - - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-ldap)) - [:span.separator - [:span.line] - [:span.text (tr "labels.or")] - [:span.line]])]) - - [:& register-form {:params params :on-success-callback on-success-callback}]]))) + [:* + (when login/show-alt-login-buttons? + [:* + [:hr {:class (stl/css :separator)}] + [:& login/login-buttons {:params params}]]) + [:hr {:class (stl/css :separator)}] + [:& register-form {:params params :on-success-callback on-success-callback}]]) (mf/defc register-page [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :auth-form)} - [:h1 {:class (stl/css :auth-title) - :data-test "registration-title"} (tr "auth.register-title")] - [:div {:class (stl/css :auth-subtitle)} (tr "auth.register-subtitle")] + [:div {:class (stl/css :auth-form)} + [:h1 {:class (stl/css :auth-title) + :data-test "registration-title"} (tr "auth.register-title")] + [:div {:class (stl/css :auth-subtitle)} (tr "auth.register-subtitle")] - (when (contains? cf/flags :demo-warning) - [:& demo-warning]) + (when (contains? cf/flags :demo-warning) + [:& demo-warning]) - [:& register-methods {:params params}] + [:& register-methods {:params params}] - [:div {:class (stl/css :links)} - [:div {:class (stl/css :link-entry :account)} - [:span (tr "auth.already-have-account") " "] + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry :account)} + [:span (tr "auth.already-have-account") " "] - [:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params)) - :data-test "login-here-link"} - (tr "auth.login-here")]] + [:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params)) + :data-test "login-here-link"} + (tr "auth.login-here")]] - (when (contains? cf/flags :demo-users) - [:div {:class (stl/css :link-entry :demo-users)} - [:span (tr "auth.create-demo-profile") " "] - [:& lk/link {:action #(st/emit! (du/create-demo-profile))} - (tr "auth.create-demo-account")]])]] - - ;; OLD - [:div.form-container - [:h1 {:data-test "registration-title"} (tr "auth.register-title")] - [:div.subtitle (tr "auth.register-subtitle")] - - (when (contains? cf/flags :demo-warning) - [:& demo-warning]) - - [:& register-methods {:params params}] - - [:div.links - [:div.link-entry - [:span (tr "auth.already-have-account") " "] - - [:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params)) - :data-test "login-here-link"} - (tr "auth.login-here")]] - - (when (contains? cf/flags :demo-users) - [:div.link-entry - [:span (tr "auth.create-demo-profile") " "] - [:& lk/link {:action #(st/emit! (du/create-demo-profile))} - (tr "auth.create-demo-account")]])]]))) + (when (contains? cf/flags :demo-users) + [:div {:class (stl/css :link-entry :demo-users)} + [:span (tr "auth.create-demo-profile") " "] + [:& lk/link {:action #(st/emit! (du/create-demo-profile))} + (tr "auth.create-demo-account")]])]]) ;; --- PAGE: register validation @@ -284,8 +213,7 @@ (mf/defc register-validate-form [{:keys [params on-success-callback] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - form (fm/use-form :spec ::register-validate-form + (let [form (fm/use-form :spec ::register-validate-form :validators [(fm/validate-not-empty :fullname (tr "auth.name.not-all-space")) (fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))] :initial params) @@ -306,103 +234,55 @@ (rx/subs! on-success (partial handle-register-error form))))))] - (if new-css-system - [:& fm/form {:on-submit on-submit :form form} - [:div {:class (stl/css :fields-row)} - [:& fm/input {:name :fullname - :label (tr "auth.fullname") - :type "text" - :show-success? true - :class (stl/css :form-field)}]] + [:& fm/form {:on-submit on-submit :form form} + [:div {:class (stl/css :fields-row)} + [:& fm/input {:name :fullname + :label (tr "auth.fullname") + :type "text" + :show-success? true + :class (stl/css :form-field)}]] - (when (contains? cf/flags :terms-and-privacy-checkbox) - (let [terms-label - (mf/html - [:& tr-html - {:tag-name "div" - :label "auth.terms-privacy-agreement-md" - :params [cf/terms-of-service-uri cf/privacy-policy-uri]}])] - [:div {:class (stl/css :fields-row :input-visible :accept-terms-and-privacy-wrapper)} - [:& fm/input {:name :accept-terms-and-privacy - :class "check-primary" - :type "checkbox" - :label terms-label}]])) - - [:> fm/submit-button* - {:label (tr "auth.register-submit") - :disabled @submitted? - :class (stl/css :register-btn)}]] - - ;; OLD - [:& fm/form {:on-submit on-submit - :form form} - [:div.fields-row - [:& fm/input {:name :fullname - :label (tr "auth.fullname") - :type "text"}]] - - (when (contains? cf/flags :terms-and-privacy-checkbox) - [:div.fields-row.input-visible.accept-terms-and-privacy-wrapper + (when (contains? cf/flags :terms-and-privacy-checkbox) + (let [terms-label + (mf/html + [:& tr-html + {:tag-name "div" + :label "auth.terms-privacy-agreement-md" + :params [cf/terms-of-service-uri cf/privacy-policy-uri]}])] + [:div {:class (stl/css :fields-row :input-visible :accept-terms-and-privacy-wrapper)} [:& fm/input {:name :accept-terms-and-privacy :class "check-primary" - :type "checkbox"} - [:span - (tr "auth.terms-privacy-agreement")]] - [:div.auth-links - [:a {:href "https://penpot.app/terms" :target "_blank"} (tr "auth.terms-of-service")] - [:span ",\u00A0"] - [:a {:href "https://penpot.app/privacy" :target "_blank"} (tr "auth.privacy-policy")]]]) + :type "checkbox" + :label terms-label}]])) - [:> fm/submit-button* - {:label (tr "auth.register-submit") - :disabled @submitted?}]]))) + [:> fm/submit-button* + {:label (tr "auth.register-submit") + :disabled @submitted? + :class (stl/css :register-btn)}]])) (mf/defc register-validate-page [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :auth-form)} - [:h1 {:class (stl/css :auth-title) - :data-test "register-title"} (tr "auth.register-title")] - [:div {:class (stl/css :auth-subtitle)} (tr "auth.register-subtitle")] + [:div {:class (stl/css :auth-form)} + [:h1 {:class (stl/css :auth-title) + :data-test "register-title"} (tr "auth.register-title")] + [:div {:class (stl/css :auth-subtitle)} (tr "auth.register-subtitle")] - [:hr {:class (stl/css :separator)}] + [:hr {:class (stl/css :separator)}] - [:& register-validate-form {:params params}] + [:& register-validate-form {:params params}] - [:div {:class (stl/css :links)} - [:div {:class (stl/css :link-entry :go-back)} - [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))} - (tr "labels.go-back")]]]] - - ;; OLD - [:div.form-container - [:h1 {:data-test "register-title"} (tr "auth.register-title")] - [:div.subtitle (tr "auth.register-subtitle")] - - [:& register-validate-form {:params params}] - - [:div.links - [:div.link-entry - [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))} - (tr "labels.go-back")]]]]))) + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry :go-back)} + [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))} + (tr "labels.go-back")]]]]) (mf/defc register-success-page [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :auth-form :register-success)} - [:div {:class (stl/css :notification-icon)} i/icon-verify] - [:div {:class (stl/css :notification-text)} (tr "auth.verification-email-sent")] - [:div {:class (stl/css :notification-text-email)} (:email params "")] - [:div {:class (stl/css :notification-text)} (tr "auth.check-your-email")]] - - ;; OLD - [:div.form-container - [:div.notification-icon i/icon-verify] - [:div.notification-text (tr "auth.verification-email-sent")] - [:div.notification-text-email (:email params "")] - [:div.notification-text (tr "auth.check-your-email")]]))) + [:div {:class (stl/css :auth-form :register-success)} + [:div {:class (stl/css :notification-icon)} i/icon-verify] + [:div {:class (stl/css :notification-text)} (tr "auth.verification-email-sent")] + [:div {:class (stl/css :notification-text-email)} (:email params "")] + [:div {:class (stl/css :notification-text)} (tr "auth.check-your-email")]]) diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs index 7d053ab1eb..2e2c359b0b 100644 --- a/frontend/src/app/main/ui/comments.cljs +++ b/frontend/src/app/main/ui/comments.cljs @@ -18,7 +18,6 @@ [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -81,20 +80,18 @@ (set! (.-height (.-style node)) "0") (set! (.-height (.-style node)) (str (+ 2 (.-scrollHeight node)) "px"))))) - [:textarea - {:ref local-ref - :auto-focus autofocus? - :on-key-down on-key-down - :on-focus on-focus* - :on-blur on-blur - :value value - :placeholder placeholder - :on-change on-change*}])) + [:textarea {:ref local-ref + :auto-focus autofocus? + :on-key-down on-key-down + :on-focus on-focus* + :on-blur on-blur + :value value + :placeholder placeholder + :on-change on-change*}])) (mf/defc reply-form [{:keys [thread] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - show-buttons? (mf/use-state false) + (let [show-buttons? (mf/use-state false) content (mf/use-state "") disabled? (or (fm/all-spaces? @content) @@ -123,54 +120,32 @@ (fn [] (st/emit! (dcm/add-comment thread @content)) (on-cancel)))] - (if new-css-system - [:div {:class (stl/css :reply-form)} - [:& resizing-textarea {:value @content - :placeholder "Reply" - :on-blur on-blur - :on-focus on-focus - :select-on-focus? false - :on-ctrl-enter on-submit - :on-change on-change}] - (when (or @show-buttons? (seq @content)) - [:div {:class (stl/css :buttons-wrapper)} - [:input.btn-secondary - {:type "button" - :class (stl/css :cancel-btn) - :value "Cancel" - :on-click on-cancel}] - [:input - {:type "button" - :class (stl/css-case :post-btn true - :global/disabled disabled?) - :value "Post" - :on-click on-submit - :disabled disabled?}]])] - - - [:div.reply-form - [:& resizing-textarea {:value @content - :placeholder "Reply" - :on-blur on-blur - :on-focus on-focus - :on-ctrl-enter on-submit - :on-change on-change}] - (when (or @show-buttons? (seq @content)) - [:div.buttons - [:input.btn-primary - {:type "button" - :value "Post" - :on-click on-submit - :disabled disabled?}] - [:input.btn-secondary - {:type "button" - :value "Cancel" - :on-click on-cancel}]])]))) + [:div {:class (stl/css :reply-form)} + [:& resizing-textarea {:value @content + :placeholder "Reply" + :on-blur on-blur + :on-focus on-focus + :select-on-focus? false + :on-ctrl-enter on-submit + :on-change on-change}] + (when (or @show-buttons? (seq @content)) + [:div {:class (stl/css :buttons-wrapper)} + [:input.btn-secondary + {:type "button" + :class (stl/css :cancel-btn) + :value "Cancel" + :on-click on-cancel}] + [:input + {:type "button" + :class (stl/css-case :post-btn true + :global/disabled disabled?) + :value "Post" + :on-click on-submit + :disabled disabled?}]])])) (mf/defc draft-thread [{:keys [draft zoom on-cancel on-submit position-modifier]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - position (cond-> (:position draft) + (let [position (cond-> (:position draft) (some? position-modifier) (gpt/transform position-modifier)) content (:content draft) @@ -201,73 +176,42 @@ (mf/deps draft) (partial on-submit draft))] + [:* + [:div + {:class (stl/css :floating-thread-bubble) + :style {:top (str pos-y "px") + :left (str pos-x "px")} + :on-click dom/stop-propagation} + "?"] + [:div {:class (stl/css :thread-content) + :style {:top (str (- pos-y 24) "px") + :left (str (+ pos-x 28) "px")} + :on-click dom/stop-propagation} + [:div {:class (stl/css :reply-form)} + [:& resizing-textarea {:placeholder (tr "labels.write-new-comment") + :value (or content "") + :autofocus true + :select-on-focus? false + :on-esc on-esc + :on-change on-change + :on-ctrl-enter on-submit}] + [:div {:class (stl/css :buttons-wrapper)} - (if new-css-system - [:* - [:div - {:class (stl/css :floating-thread-bubble) - :style {:top (str pos-y "px") - :left (str pos-x "px")} - :on-click dom/stop-propagation} - "?"] - [:div {:class (stl/css :thread-content) - :style {:top (str (- pos-y 24) "px") - :left (str (+ pos-x 28) "px")} - :on-click dom/stop-propagation} - [:div {:class (stl/css :reply-form)} - [:& resizing-textarea {:placeholder (tr "labels.write-new-comment") - :value (or content "") - :autofocus true - :select-on-focus? false - :on-esc on-esc - :on-change on-change - :on-ctrl-enter on-submit}] - [:div {:class (stl/css :buttons-wrapper)} + [:input {:on-click on-esc + :class (stl/css :cancel-btn) + :type "button" + :value "Cancel"}] - [:input {:on-click on-esc - :class (stl/css :cancel-btn) - :type "button" - :value "Cancel"}] - - [:input {:on-click on-submit - :type "button" - :value "Post" - :class (stl/css-case :post-btn true - :global/disabled disabled?) - :disabled disabled?}]]]]] - - [:* - [:div.thread-bubble - {:style {:top (str pos-y "px") - :left (str pos-x "px")} - :on-click dom/stop-propagation} - [:span "?"]] - [:div.thread-content - {:style {:top (str (- pos-y 14) "px") - :left (str (+ pos-x 14) "px")} - :on-click dom/stop-propagation} - [:div.reply-form - [:& resizing-textarea {:placeholder (tr "labels.write-new-comment") - :value (or content "") - :autofocus true - :on-esc on-esc - :on-ctrl-enter on-submit - :on-change on-change}] - [:div.buttons - [:input.btn-primary - {:on-click on-submit - :type "button" - :value "Post" - :disabled disabled?}] - [:input.btn-secondary - {:on-click on-esc - :type "button" - :value "Cancel"}]]]]]))) + [:input {:on-click on-submit + :type "button" + :value "Post" + :class (stl/css-case :post-btn true + :global/disabled disabled?) + :disabled disabled?}]]]]])) (mf/defc edit-form [{:keys [content on-submit on-cancel] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - content (mf/use-state content) + (let [content (mf/use-state content) on-change (mf/use-fn @@ -281,44 +225,28 @@ disabled? (or (fm/all-spaces? @content) (str/empty-or-nil? @content))] - (if new-css-system - [:div {:class (stl/css :edit-form)} - [:& resizing-textarea {:value @content - :autofocus true - :select-on-focus true - :select-on-focus? false - :on-ctrl-enter on-submit* - :on-change on-change}] - [:div {:class (stl/css :buttons-wrapper)} - [:input {:type "button" - :value "Cancel" - :class (stl/css :cancel-btn) - :on-click on-cancel}] - [:input {:type "button" - :class (stl/css-case :post-btn true - :global/disabled disabled?) - :value "Post" - :on-click on-submit* - :disabled disabled?}]]] - - - [:div.reply-form.edit-form - [:& resizing-textarea {:value @content - :autofocus true - :select-on-focus true - :on-ctrl-enter on-submit* - :on-change on-change}] - [:div.buttons - [:input.btn-primary {:type "button" - :value "Post" - :on-click on-submit* - :disabled disabled?}] - [:input.btn-secondary {:type "button" :value "Cancel" :on-click on-cancel}]]]))) + [:div {:class (stl/css :edit-form)} + [:& resizing-textarea {:value @content + :autofocus true + :select-on-focus true + :select-on-focus? false + :on-ctrl-enter on-submit* + :on-change on-change}] + [:div {:class (stl/css :buttons-wrapper)} + [:input {:type "button" + :value "Cancel" + :class (stl/css :cancel-btn) + :on-click on-cancel}] + [:input {:type "button" + :class (stl/css-case :post-btn true + :global/disabled disabled?) + :value "Post" + :on-click on-submit* + :disabled disabled?}]]])) (mf/defc comment-item [{:keys [comment thread users origin] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - owner (get users (:owner-id comment)) + (let [owner (get users (:owner-id comment)) profile (mf/deref refs/profile) options (mf/use-state false) edition? (mf/use-state false) @@ -382,82 +310,46 @@ (dom/stop-propagation event) (st/emit! (dcm/update-comment-thread (update thread :is-resolved not)))))] - (if new-css-system - [:div {:class (stl/css :comment-container)} - [:div {:class (stl/css :comment)} - [:div {:class (stl/css :author)} - [:div {:class (stl/css :avatar)} - [:img {:src (cfg/resolve-profile-photo-url owner)}]] - [:div {:class (stl/css :name)} - [:div {:class (stl/css :fullname)} (:fullname owner)] - [:div {:class (stl/css :timeago)} (dt/timeago (:modified-at comment))]] + [:div {:class (stl/css :comment-container)} + [:div {:class (stl/css :comment)} + [:div {:class (stl/css :author)} + [:div {:class (stl/css :avatar)} + [:img {:src (cfg/resolve-profile-photo-url owner)}]] + [:div {:class (stl/css :name)} + [:div {:class (stl/css :fullname)} (:fullname owner)] + [:div {:class (stl/css :timeago)} (dt/timeago (:modified-at comment))]] - (when (some? thread) - [:div {:class (stl/css :options-resolve-wrapper) - :on-click toggle-resolved} - [:span {:class (stl/css-case :options-resolve true - :global/checked (:is-resolved thread))} i/tick-refactor]]) + (when (some? thread) + [:div {:class (stl/css :options-resolve-wrapper) + :on-click toggle-resolved} + [:span {:class (stl/css-case :options-resolve true + :global/checked (:is-resolved thread))} i/tick-refactor]]) - (when (= (:id profile) (:id owner)) - [:div {:class (stl/css :options) - :on-click on-toggle-options} - i/menu-refactor])] + (when (= (:id profile) (:id owner)) + [:div {:class (stl/css :options) + :on-click on-toggle-options} + i/menu-refactor])] - [:div {:class (stl/css :content)} - (if @edition? - [:& edit-form {:content (:content comment) - :on-submit on-submit - :on-cancel on-cancel}] - [:span {:class (stl/css :text)} (:content comment)])]] + [:div {:class (stl/css :content)} + (if @edition? + [:& edit-form {:content (:content comment) + :on-submit on-submit + :on-cancel on-cancel}] + [:span {:class (stl/css :text)} (:content comment)])]] - [:& dropdown {:show @options - :on-close on-hide-options} - [:ul {:class (stl/css :comment-options-dropdown)} + [:& dropdown {:show @options + :on-close on-hide-options} + [:ul {:class (stl/css :comment-options-dropdown)} + [:li {:class (stl/css :context-menu-option) + :on-click on-edit-clicked} + (tr "labels.edit")] + (if thread [:li {:class (stl/css :context-menu-option) - :on-click on-edit-clicked} - (tr "labels.edit")] - (if thread - [:li {:class (stl/css :context-menu-option) - :on-click on-delete-thread} - (tr "labels.delete-comment-thread")] - [:li {:class (stl/css :context-menu-option) - :on-click on-delete-comment} - (tr "labels.delete-comment")])]]] - - - [:div.comment-container - [:div.comment - [:div.author - [:div.avatar - [:img {:src (cfg/resolve-profile-photo-url owner)}]] - [:div.name - [:div.fullname (:fullname owner)] - [:div.timeago (dt/timeago (:modified-at comment))]] - - (when (some? thread) - [:div.options-resolve {:on-click toggle-resolved} - (if (:is-resolved thread) - [:span i/checkbox-checked] - [:span i/checkbox-unchecked])]) - - (when (= (:id profile) (:id owner)) - [:div.options - [:div.options-icon {:on-click on-toggle-options} i/actions]])] - - [:div.content - (if @edition? - [:& edit-form {:content (:content comment) - :on-submit on-submit - :on-cancel on-cancel}] - [:span.text (:content comment)])]] - - [:& dropdown {:show @options - :on-close on-hide-options} - [:ul.dropdown.comment-options-dropdown - [:li {:on-click on-edit-clicked} (tr "labels.edit")] - (if thread - [:li {:on-click on-delete-thread} (tr "labels.delete-comment-thread")] - [:li {:on-click on-delete-comment} (tr "labels.delete-comment")])]]]))) + :on-click on-delete-thread} + (tr "labels.delete-comment-thread")] + [:li {:class (stl/css :context-menu-option) + :on-click on-delete-comment} + (tr "labels.delete-comment")])]]])) (defn make-comments-ref [thread-id] @@ -466,8 +358,7 @@ (mf/defc thread-comments {::mf/wrap [mf/memo]} [{:keys [thread zoom users origin position-modifier]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - ref (mf/use-ref) + (let [ref (mf/use-ref) thread-id (:id thread) @@ -477,12 +368,8 @@ (some? position-modifier) (gpt/transform position-modifier)) - pos-x (if new-css-system - (+ (* (:x pos) zoom) 24) - (+ (* (:x pos) zoom) 14)) - pos-y (if new-css-system - (- (* (:y pos) zoom) 28) - (- (* (:y pos) zoom) 14)) + pos-x (+ (* (:x pos) zoom) 24) + pos-y (- (* (:y pos) zoom) 28) comments-ref (mf/with-memo [thread-id] @@ -504,46 +391,24 @@ (mf/with-layout-effect [thread-pos comments-map] (when-let [node (mf/ref-val ref)] (dom/scroll-into-view-if-needed! node))) - (if new-css-system - (when (some? comment) - [:div {:class (stl/css :thread-content) - :style {:top (str pos-y "px") - :left (str pos-x "px")} - :on-click dom/stop-propagation} + (when (some? comment) + [:div {:class (stl/css :thread-content) + :style {:top (str pos-y "px") + :left (str pos-x "px")} + :on-click dom/stop-propagation} - [:div {:class (stl/css :comments)} - [:& comment-item {:comment comment - :users users - :thread thread - :origin origin}] - (for [item (rest comments)] - [:* {:key (dm/str (:id item))} - [:& comment-item {:comment item - :users users - :origin origin}]]) - [:div {:ref ref}]] - [:& reply-form {:thread thread}]]) - - - (when (some? comment) - [:div.thread-content - {:style {:top (str pos-y "px") - :left (str pos-x "px")} - :on-click dom/stop-propagation} - - [:div.comments - [:& comment-item {:comment comment - :users users - :thread thread - :origin origin}] - (for [item (rest comments)] - [:* {:key (dm/str (:id item))} - [:hr] - [:& comment-item {:comment item - :users users - :origin origin}]]) - [:div {:ref ref}]] - [:& reply-form {:thread thread}]])))) + [:div {:class (stl/css :comments)} + [:& comment-item {:comment comment + :users users + :thread thread + :origin origin}] + (for [item (rest comments)] + [:* {:key (dm/str (:id item))} + [:& comment-item {:comment item + :users users + :origin origin}]]) + [:div {:ref ref}]] + [:& reply-form {:thread thread}]]))) (defn use-buble [zoom {:keys [position frame-id]}] @@ -602,8 +467,7 @@ (mf/defc thread-bubble {::mf/wrap [mf/memo]} [{:keys [thread zoom open? on-click origin position-modifier]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - pos (cond-> (:position thread) + (let [pos (cond-> (:position thread) (some? position-modifier) (gpt/transform position-modifier)) @@ -658,37 +522,22 @@ (dom/stop-propagation event) (when (= origin :viewer) (on-click thread))))] - (if new-css-system - [:div {:style {:top (str pos-y "px") - :left (str pos-x "px")} - :on-pointer-down on-pointer-down* - :on-pointer-up on-pointer-up* - :on-pointer-move on-pointer-move* - :on-click on-click* - :on-lost-pointer-capture on-lost-pointer-capture - :class (stl/css-case - :floating-thread-bubble true - :resolved (:is-resolved thread) - :unread (pos? (:count-unread-comments thread)))} - [:span (:seqn thread)]] - - [:div.thread-bubble - {:style {:top (str pos-y "px") - :left (str pos-x "px")} - :on-pointer-down on-pointer-down* - :on-pointer-up on-pointer-up* - :on-pointer-move on-pointer-move* - :on-click on-click* - :on-lost-pointer-capture on-lost-pointer-capture - :class (dom/classnames - :resolved (:is-resolved thread) - :unread (pos? (:count-unread-comments thread)))} - [:span (:seqn thread)]]))) + [:div {:style {:top (str pos-y "px") + :left (str pos-x "px")} + :on-pointer-down on-pointer-down* + :on-pointer-up on-pointer-up* + :on-pointer-move on-pointer-move* + :on-click on-click* + :on-lost-pointer-capture on-lost-pointer-capture + :class (stl/css-case + :floating-thread-bubble true + :resolved (:is-resolved thread) + :unread (pos? (:count-unread-comments thread)))} + [:span (:seqn thread)]])) (mf/defc comment-thread [{:keys [item users on-click]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - owner (get users (:owner-id item)) + (let [owner (get users (:owner-id item)) on-click* (mf/use-fn (mf/deps item) @@ -698,99 +547,50 @@ (when (fn? on-click) (on-click item))))] - (if new-css-system - [:div {:class (stl/css :comment) - :on-click on-click*} - [:div {:class (stl/css :author)} - [:div {:class (stl/css-case :thread-bubble true - :resolved (:is-resolved item) - :unread (pos? (:count-unread-comments item)))} - (:seqn item)] - [:div {:class (stl/css :avatar)} - [:img {:src (cfg/resolve-profile-photo-url owner)}]] - [:div {:class (stl/css :name)} - [:div {:class (stl/css :fullname)} (:fullname owner)] - [:div {:class (stl/css :timeago)} (dt/timeago (:modified-at item))]]] - [:div {:class (stl/css :content)} - (:content item)] - [:div {:class (stl/css :replies)} - (let [unread (:count-unread-comments item ::none) - total (:count-comments item 1)] - [:* - (when (> total 1) - (if (= total 2) - [:span {:class (stl/css :total-replies)} "1 reply"] - [:span {:class (stl/css :total-replies)} (str (dec total) " replies")])) + [:div {:class (stl/css :comment) + :on-click on-click*} + [:div {:class (stl/css :author)} + [:div {:class (stl/css-case :thread-bubble true + :resolved (:is-resolved item) + :unread (pos? (:count-unread-comments item)))} + (:seqn item)] + [:div {:class (stl/css :avatar)} + [:img {:src (cfg/resolve-profile-photo-url owner)}]] + [:div {:class (stl/css :name)} + [:div {:class (stl/css :fullname)} (:fullname owner)] + [:div {:class (stl/css :timeago)} (dt/timeago (:modified-at item))]]] + [:div {:class (stl/css :content)} + (:content item)] + [:div {:class (stl/css :replies)} + (let [unread (:count-unread-comments item ::none) + total (:count-comments item 1)] + [:* + (when (> total 1) + (if (= total 2) + [:span {:class (stl/css :total-replies)} "1 reply"] + [:span {:class (stl/css :total-replies)} (str (dec total) " replies")])) - (when (and (> total 1) (> unread 0)) - (if (= unread 1) - [:span {:class (stl/css :new-replies)} "1 new reply"] - [:span {:class (stl/css :new-replies)} (str unread " new replies")]))])]] - - - [:div.comment {:on-click on-click*} - [:div.author - [:div.thread-bubble - {:class (dom/classnames - :resolved (:is-resolved item) - :unread (pos? (:count-unread-comments item)))} - (:seqn item)] - [:div.avatar - [:img {:src (cfg/resolve-profile-photo-url owner)}]] - [:div.name - [:div.fullname (:fullname owner) ", "] - [:div.timeago (dt/timeago (:modified-at item))]]] - [:div.content - [:span.text (:content item)]] - [:div.content.replies - (let [unread (:count-unread-comments item ::none) - total (:count-comments item 1)] - [:* - (when (> total 1) - (if (= total 2) - [:span.total-replies "1 reply"] - [:span.total-replies (str (dec total) " replies")])) - - (when (and (> total 1) (> unread 0)) - (if (= unread 1) - [:span.new-replies "1 new reply"] - [:span.new-replies (str unread " new replies")]))])]]))) + (when (and (> total 1) (> unread 0)) + (if (= unread 1) + [:span {:class (stl/css :new-replies)} "1 new reply"] + [:span {:class (stl/css :new-replies)} (str unread " new replies")]))])]])) (mf/defc comment-thread-group [{:keys [group users on-thread-click]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :thread-group)} - (if (:file-name group) - [:div {:class (stl/css :section-title)} - [:span {:class (stl/css :file-name)} (:file-name group) ", "] - [:span {:class (stl/css :page-name)} (:page-name group)]] + [:div {:class (stl/css :thread-group)} + (if (:file-name group) + [:div {:class (stl/css :section-title)} + [:span {:class (stl/css :file-name)} (:file-name group) ", "] + [:span {:class (stl/css :page-name)} (:page-name group)]] - [:div {:class (stl/css :section-title)} - [:span {:class (stl/css :icon)} i/document-refactor] - [:span {:class (stl/css :page-name)} (:page-name group)]]) + [:div {:class (stl/css :section-title)} + [:span {:class (stl/css :icon)} i/document-refactor] + [:span {:class (stl/css :page-name)} (:page-name group)]]) - [:div {:class (stl/css :threads)} - (for [item (:items group)] - [:& comment-thread - {:item item - :on-click on-thread-click - :users users - :key (:id item)}])]] - - - [:div.thread-group - (if (:file-name group) - [:div.section-title - [:span.label.filename (:file-name group) ", "] - [:span.label (:page-name group)]] - [:div.section-title - [:span.icon i/file-html] - [:span.label (:page-name group)]]) - [:div.threads - (for [item (:items group)] - [:& comment-thread - {:item item - :on-click on-thread-click - :users users - :key (:id item)}])]]))) + [:div {:class (stl/css :threads)} + (for [item (:items group)] + [:& comment-thread + {:item item + :on-click on-thread-click + :users users + :key (:id item)}])]]) diff --git a/frontend/src/app/main/ui/comments.scss b/frontend/src/app/main/ui/comments.scss index 89fc247d70..874a229ad3 100644 --- a/frontend/src/app/main/ui/comments.scss +++ b/frontend/src/app/main/ui/comments.scss @@ -13,96 +13,106 @@ border-radius: $br-8; padding: $s-8 $s-16; - .section-title { - @include titleTipography; - height: $s-32; - display: flex; - align-items: center; - margin-bottom: $s-8; - .file-name { - color: var(--comment-subtitle-color); - } - .page-name { - color: var(--comment-subtitle-color); - } - .icon { - display: flex; - align-items: center; - padding: 0 $s-6 0 $s-4; - width: $s-24; - height: $s-32; - margin-left: $s-6; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - } - .threads { - display: flex; - flex-direction: column; - gap: $s-24; - } - &:hover { background: $db-primary; } } +.section-title { + @include titleTipography; + height: $s-32; + display: flex; + align-items: center; + margin-bottom: $s-8; +} + +.file-name { + color: var(--comment-subtitle-color); +} + +.page-name { + color: var(--comment-subtitle-color); +} + +.icon { + display: flex; + align-items: center; + padding: 0 $s-6 0 $s-4; + width: $s-24; + height: $s-32; + margin-left: $s-6; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } +} + +.threads { + display: flex; + flex-direction: column; + gap: $s-24; +} + // Comment-thread .comment { @include titleTipography; display: flex; flex-direction: column; gap: $s-12; - .author { - display: flex; - gap: $s-8; - .thread-bubble { - @extend .comment-bubbles; - &.resolved { - @extend .resolved-comment-bubble; - } - &.unread { - @extend .unread-comment-bubble; - } - } - .avatar { - height: $s-32; - width: $s-32; - border-radius: $br-circle; - img { - border-radius: $br-circle; - } - } - .name { - flex-grow: 1; - .fullname { - @include textEllipsis; - color: var(--comment-title-color); - } - .timeago { - @include textEllipsis; - color: var(--comment-subtitle-color); - } - } +} + +.author { + display: flex; + gap: $s-8; +} + +.thread-bubble { + @extend .comment-bubbles; + &.resolved { + @extend .resolved-comment-bubble; } - .content { - @include titleTipography; - color: var(--color-foreground-primary); - } - .replies { - display: flex; - gap: $s-8; - .total-replies { - color: var(--color-foreground-secondary); - } - .new-replies { - color: var(--color-accent-primary); - } + &.unread { + @extend .unread-comment-bubble; } } +.avatar { + height: $s-32; + width: $s-32; + border-radius: $br-circle; + img { + border-radius: $br-circle; + } +} + +.name { + flex-grow: 1; + .fullname { + @include textEllipsis; + color: var(--comment-title-color); + } + .timeago { + @include textEllipsis; + color: var(--comment-subtitle-color); + } +} + +.content { + @include titleTipography; + color: var(--color-foreground-primary); +} + +.replies { + display: flex; + gap: $s-8; +} + +.total-replies { + color: var(--color-foreground-secondary); +} +.new-replies { + color: var(--color-accent-primary); +} // Thread-bubble .floating-thread-bubble { diff --git a/frontend/src/app/main/ui/components/file_uploader.cljs b/frontend/src/app/main/ui/components/file_uploader.cljs index 71af00d4ed..35429e09ee 100644 --- a/frontend/src/app/main/ui/components/file_uploader.cljs +++ b/frontend/src/app/main/ui/components/file_uploader.cljs @@ -30,15 +30,14 @@ (when label-text [:label {:for input-id :class-name label-class} label-text]) - [:input - {:style {:display "none" - :width 0} - :id input-id - :multiple multi - :accept accept - :type "file" - :ref input-ref - :on-change on-files-selected - :data-test data-test - :aria-label "uploader"}]])) + [:input {:style {:display "none" + :width 0} + :id input-id + :multiple multi + :accept accept + :type "file" + :ref input-ref + :on-change on-files-selected + :data-test data-test + :aria-label "uploader"}]])) diff --git a/frontend/src/app/main/ui/confirm.cljs b/frontend/src/app/main/ui/confirm.cljs index d17cfaee91..cfce7c2c13 100644 --- a/frontend/src/app/main/ui/confirm.cljs +++ b/frontend/src/app/main/ui/confirm.cljs @@ -9,7 +9,6 @@ (:require [app.main.data.modal :as modal] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr t]] @@ -31,8 +30,7 @@ cancel-label accept-label accept-style] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - locale (mf/deref i18n/locale) + (let [locale (mf/deref i18n/locale) on-accept (or on-accept identity) on-cancel (or on-cancel identity) @@ -67,87 +65,45 @@ (partial events/unlistenByKey)))) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} title] - [:button {:class (stl/css :modal-close-btn) - :on-click cancel-fn} i/close-refactor]] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} title] + [:button {:class (stl/css :modal-close-btn) + :on-click cancel-fn} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - (when (and (string? message) (not= message "")) - [:h3 {:class (stl/css :modal-msg)} message]) - (when (and (string? scd-message) (not= scd-message "")) - [:h3 {:class (stl/css :modal-scd-msg)} scd-message]) - (when (string? hint) - [:p {:class (stl/css :modal-hint)} hint]) - (when (> (count items) 0) - [:* - [:p {:class (stl/css :modal-subtitle)} - (tr "ds.component-subtitle")] - [:ul {:class (stl/css :component-list)} - (for [item items] - [:li {:class (stl/css :modal-item-element)} - [:span {:class (stl/css :modal-component-icon)} - i/component-refactor] - [:span {:class (stl/css :modal-component-name)} - (:name item)]])]])] - - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - (when-not (= cancel-label :omit) - [:input - {:class (stl/css :cancel-button) - :type "button" - :value cancel-label - :on-click cancel-fn}]) + [:div {:class (stl/css :modal-content)} + (when (and (string? message) (not= message "")) + [:h3 {:class (stl/css :modal-msg)} message]) + (when (and (string? scd-message) (not= scd-message "")) + [:h3 {:class (stl/css :modal-scd-msg)} scd-message]) + (when (string? hint) + [:p {:class (stl/css :modal-hint)} hint]) + (when (> (count items) 0) + [:* + [:p {:class (stl/css :modal-subtitle)} + (tr "ds.component-subtitle")] + [:ul {:class (stl/css :component-list)} + (for [item items] + [:li {:class (stl/css :modal-item-element)} + [:span {:class (stl/css :modal-component-icon)} + i/component-refactor] + [:span {:class (stl/css :modal-component-name)} + (:name item)]])]])] + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + (when-not (= cancel-label :omit) [:input - {:class (stl/css-case :accept-btn true - :danger (= accept-style :danger) - :primary (= accept-style :primary)) + {:class (stl/css :cancel-button) :type "button" - :value accept-label - :on-click accept-fn}]]]]] + :value cancel-label + :on-click cancel-fn}]) - - [:div.modal-overlay - [:div.modal-container.confirm-dialog - [:div.modal-header - [:div.modal-header-title - [:h2 title]] - [:div.modal-close-button - {:on-click cancel-fn} i/close]] - - [:div.modal-content - (when (and (string? message) (not= message "")) - [:h3 message]) - (when (and (string? scd-message) (not= scd-message "")) - [:h3 scd-message]) - (when (string? hint) - [:p hint]) - (when (> (count items) 0) - [:* - [:p (tr "ds.component-subtitle")] - [:ul.component-list - (for [item items] - [:li.modal-item-element - [:span.modal-component-icon i/component] - [:span (:name item)]])]])] - - [:div.modal-footer - [:div.action-buttons - (when-not (= cancel-label :omit) - [:input.cancel-button - {:type "button" - :value cancel-label - :on-click cancel-fn}]) - - [:input.accept-button - {:class (dom/classnames - :danger (= accept-style :danger) - :primary (= accept-style :primary)) - :type "button" - :value accept-label - :on-click accept-fn}]]]]]))) + [:input + {:class (stl/css-case :accept-btn true + :danger (= accept-style :danger) + :primary (= accept-style :primary)) + :type "button" + :value accept-label + :on-click accept-fn}]]]]])) diff --git a/frontend/src/app/main/ui/confirm.scss b/frontend/src/app/main/ui/confirm.scss index 7d01aff684..ea944f3e5f 100644 --- a/frontend/src/app/main/ui/confirm.scss +++ b/frontend/src/app/main/ui/confirm.scss @@ -11,56 +11,63 @@ &.transparent { background-color: transparent; } - .modal-container { - @extend .modal-container-base; - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } - .modal-content { - @include titleTipography; - margin-bottom: $s-24; - .component-list { - .modal-item-element { - @include flexRow; - .modal-component-icon { - @include flexCenter; - height: $s-16; - width: $s-16; - svg { - @extend .button-icon-small; - stroke: var(--color); - } - } - .modal-component-name { - @include titleTipography; - } - } - } - .modal-hint { - @extend .modal-hint-base; - } - } - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-btn { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } - } +} + +.modal-container { + @extend .modal-container-base; +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + margin-bottom: $s-24; +} + +.modal-item-element { + @include flexRow; +} + +.modal-component-icon { + @include flexCenter; + height: $s-16; + width: $s-16; + svg { + @extend .button-icon-small; + stroke: var(--color); + } +} +.modal-component-name { + @include titleTipography; +} + +.modal-hint { + @extend .modal-hint-base; +} + +.action-buttons { + @extend .modal-action-btns; +} + +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; } } diff --git a/frontend/src/app/main/ui/dashboard/change_owner.cljs b/frontend/src/app/main/ui/dashboard/change_owner.cljs index bb8eb1ea7d..cae033df37 100644 --- a/frontend/src/app/main/ui/dashboard/change_owner.cljs +++ b/frontend/src/app/main/ui/dashboard/change_owner.cljs @@ -12,7 +12,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [cljs.spec.alpha :as s] @@ -26,8 +25,7 @@ {::mf/register modal/components ::mf/register-as :leave-and-reassign} [{:keys [profile team accept]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - form (fm/use-form :spec ::leave-modal-form :initial {}) + (let [form (fm/use-form :spec ::leave-modal-form :initial {}) members-map (mf/deref refs/dashboard-team-members) members (vals members-map) @@ -42,71 +40,37 @@ (let [member-id (get-in @form [:clean-data :member-id])] (accept member-id)))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} (tr "modals.leave-and-reassign.title")] - [:button {:class (stl/css :modal-close-btn) - :on-click on-cancel} i/close-refactor]] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} (tr "modals.leave-and-reassign.title")] + [:button {:class (stl/css :modal-close-btn) + :on-click on-cancel} i/close-refactor]] - [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-content)} + [:p {:class (stl/css :modal-msg)} + (tr "modals.leave-and-reassign.hint1" (:name team))] + + (if (empty? members) [:p {:class (stl/css :modal-msg)} - (tr "modals.leave-and-reassign.hint1" (:name team))] + (tr "modals.leave-and-reassign.forbidden")] + [:* + [:& fm/form {:form form} + [:& fm/select {:name :member-id + :options options}]]])] - (if (empty? members) - [:p {:class (stl/css :modal-msg)} - (tr "modals.leave-and-reassign.forbidden")] - [:* - [:& fm/form {:form form} - [:& fm/select {:name :member-id - :options options}]]])] + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:input {:class (stl/css :cancel-button) + :type "button" + :value (tr "labels.cancel") + :on-click on-cancel}] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.cancel") - :on-click on-cancel}] - - [:input.accept-button - {:type "button" - :class (stl/css-case :accept-btn true - :danger (:valid @form) - :global/disabled (not (:valid @form))) - :disabled (not (:valid @form)) - :value (tr "modals.leave-and-reassign.promote-and-leave") - :on-click on-accept}]]]]] - - - [:div.modal-overlay - [:div.modal-container.confirm-dialog - [:div.modal-header - [:div.modal-header-title - [:h2 (tr "modals.leave-and-reassign.title")]] - [:div.modal-close-button - {:on-click on-cancel} i/close]] - - [:div.modal-content.generic-form - [:p (tr "modals.leave-and-reassign.hint1" (:name team))] - - (if (empty? members) - [:p (tr "modals.leave-and-reassign.forbidden")] - [:* - [:& fm/form {:form form} - [:& fm/select {:name :member-id - :options options}]]])] - - [:div.modal-footer - [:div.action-buttons - [:input.cancel-button - {:type "button" - :value (tr "labels.cancel") - :on-click on-cancel}] - - [:input.accept-button - {:type "button" - :class (if (:valid @form) "danger" "btn-disabled") - :disabled (not (:valid @form)) - :value (tr "modals.leave-and-reassign.promote-and-leave") - :on-click on-accept}]]]]]))) + [:input.accept-button + {:type "button" + :class (stl/css-case :accept-btn true + :danger (:valid @form) + :global/disabled (not (:valid @form))) + :disabled (not (:valid @form)) + :value (tr "modals.leave-and-reassign.promote-and-leave") + :on-click on-accept}]]]]])) diff --git a/frontend/src/app/main/ui/dashboard/change_owner.scss b/frontend/src/app/main/ui/dashboard/change_owner.scss index 799d566c7c..3c91c1a92b 100644 --- a/frontend/src/app/main/ui/dashboard/change_owner.scss +++ b/frontend/src/app/main/ui/dashboard/change_owner.scss @@ -8,39 +8,46 @@ .modal-overlay { @extend .modal-overlay-base; - .modal-container { - @extend .modal-container-base; - border: $s-1 solid var(--modal-border-color); - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } - .modal-content { - @include titleTipography; - margin-bottom: $s-24; - .input-wrapper { - @extend .input-with-label; - } - } - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-btn { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } - } +} + +.modal-container { + @extend .modal-container-base; + border: $s-1 solid var(--modal-border-color); +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + margin-bottom: $s-24; +} + +.input-wrapper { + @extend .input-with-label; +} + +.action-buttons { + @extend .modal-action-btns; +} + +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; } } diff --git a/frontend/src/app/main/ui/dashboard/export.cljs b/frontend/src/app/main/ui/dashboard/export.cljs index d1ff72b124..3adee05946 100644 --- a/frontend/src/app/main/ui/dashboard/export.cljs +++ b/frontend/src/app/main/ui/dashboard/export.cljs @@ -11,7 +11,6 @@ [app.common.data.macros :as dm] [app.main.data.modal :as modal] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.worker :as uw] [app.util.dom :as dom] @@ -24,36 +23,19 @@ (mf/defc export-entry {::mf/wrap-props false} [{:keys [file]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] + [:div {:class (stl/css-case :file-entry true + :loading (:loading? file) + :success (:export-success? file) + :error (:export-error? file))} - (if new-css-system - [:div {:class (stl/css-case :file-entry true - :loading (:loading? file) - :success (:export-success? file) - :error (:export-error? file))} + [:div {:class (stl/css :file-name)} + [:span {:class (stl/css :file-icon)} + (cond (:export-success? file) i/tick-refactor + (:export-error? file) i/close-refactor + (:loading? file) i/loader-pencil)] - [:div {:class (stl/css :file-name)} - [:span {:class (stl/css :file-icon)} - (cond (:export-success? file) i/tick-refactor - (:export-error? file) i/close-refactor - (:loading? file) i/loader-pencil)] - - [:div {:class (stl/css :file-name-label)} - (:name file)]]] - - - [:div.file-entry - {:class (dom/classnames - :loading (:loading? file) - :success (:export-success? file) - :error (:export-error? file))} - [:div.file-name - [:div.file-icon - (cond (:export-success? file) i/tick - (:export-error? file) i/close - (:loading? file) i/loader-pencil)] - - [:div.file-name-label (:name file)]]]))) + [:div {:class (stl/css :file-name-label)} + (:name file)]]]) (defn- mark-file-error [files file-id] @@ -79,8 +61,7 @@ ::mf/register-as :export ::mf/wrap-props false} [{:keys [team-id files has-libraries? binary? features]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - state* (mf/use-state + (let [state* (mf/use-state #(let [files (mapv (fn [file] (assoc file :loading? true)) files)] {:status :prepare :selected :all @@ -140,136 +121,70 @@ (when-not has-libraries? (start-export))) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} - (tr "dashboard.export.title")] - [:button {:class (stl/css :modal-close-btn) - :on-click on-cancel} i/close-refactor]] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} + (tr "dashboard.export.title")] + [:button {:class (stl/css :modal-close-btn) + :on-click on-cancel} i/close-refactor]] - (cond - (= status :prepare) - [:* - [:div {:class (stl/css :modal-content)} - [:p {:class (stl/css :modal-msg)} (tr "dashboard.export.explain")] - [:p {:class (stl/css :modal-scd-msg)} (tr "dashboard.export.detail")] + (cond + (= status :prepare) + [:* + [:div {:class (stl/css :modal-content)} + [:p {:class (stl/css :modal-msg)} (tr "dashboard.export.explain")] + [:p {:class (stl/css :modal-scd-msg)} (tr "dashboard.export.detail")] - (for [type export-types] - [:div {:class (stl/css :export-option true) - :key (name type)} - [:label {:for (str "export-" type) - :class (stl/css-case :global/checked (= selected type))} - ;; Execution time translation strings: - ;; dashboard.export.options.all.message - ;; dashboard.export.options.all.title - ;; dashboard.export.options.detach.message - ;; dashboard.export.options.detach.title - ;; dashboard.export.options.merge.message - ;; dashboard.export.options.merge.title - [:span {:class (stl/css-case :global/checked (= selected type))} - (when (= selected type) - i/status-tick-refactor)] - [:div {:class (stl/css :option-content)} - [:h3 {:class (stl/css :modal-subtitle)} (tr (dm/str "dashboard.export.options." (d/name type) ".title"))] - [:p {:class (stl/css :modal-msg)} (tr (dm/str "dashboard.export.options." (d/name type) ".message"))]] + (for [type export-types] + [:div {:class (stl/css :export-option true) + :key (name type)} + [:label {:for (str "export-" type) + :class (stl/css-case :global/checked (= selected type))} + ;; Execution time translation strings: + ;; dashboard.export.options.all.message + ;; dashboard.export.options.all.title + ;; dashboard.export.options.detach.message + ;; dashboard.export.options.detach.title + ;; dashboard.export.options.merge.message + ;; dashboard.export.options.merge.title + [:span {:class (stl/css-case :global/checked (= selected type))} + (when (= selected type) + i/status-tick-refactor)] + [:div {:class (stl/css :option-content)} + [:h3 {:class (stl/css :modal-subtitle)} (tr (dm/str "dashboard.export.options." (d/name type) ".title"))] + [:p {:class (stl/css :modal-msg)} (tr (dm/str "dashboard.export.options." (d/name type) ".message"))]] - [:input {:type "radio" - :class (stl/css :option-input) - :id (str "export-" type) - :checked (= selected type) - :name "export-option" - :data-type (name type) - :on-change on-change}]]])] + [:input {:type "radio" + :class (stl/css :option-input) + :id (str "export-" type) + :checked (= selected type) + :name "export-option" + :data-type (name type) + :on-change on-change}]]])] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.cancel") - :on-click on-cancel}] + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:input {:class (stl/css :cancel-button) + :type "button" + :value (tr "labels.cancel") + :on-click on-cancel}] - [:input {:class (stl/css :accept-btn) - :type "button" - :value (tr "labels.continue") - :on-click on-accept}]]]] + [:input {:class (stl/css :accept-btn) + :type "button" + :value (tr "labels.continue") + :on-click on-accept}]]]] - (= status :exporting) - [:* - [:div {:class (stl/css :modal-content)} - (for [file (:files state)] - [:& export-entry {:file file :key (dm/str (:id file))}])] + (= status :exporting) + [:* + [:div {:class (stl/css :modal-content)} + (for [file (:files state)] + [:& export-entry {:file file :key (dm/str (:id file))}])] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:input {:class (stl/css :accept-btn) - :type "button" - :value (tr "labels.close") - :disabled (->> state :files (some :loading?)) - :on-click on-cancel}]]]])]] - - - [:div.modal-overlay - [:div.modal-container.export-dialog - [:div.modal-header - [:div.modal-header-title - [:h2 (tr "dashboard.export.title")]] - - [:div.modal-close-button - {:on-click on-cancel} i/close]] - - (cond - (= status :prepare) - [:* - [:div.modal-content - [:p.explain (tr "dashboard.export.explain")] - [:p.detail (tr "dashboard.export.detail")] - - (for [type export-types] - [:div.export-option {:class (when (= selected type) "selected") - :key (name type)} - [:label.option-container - ;; Execution time translation strings: - ;; dashboard.export.options.all.message - ;; dashboard.export.options.all.title - ;; dashboard.export.options.detach.message - ;; dashboard.export.options.detach.title - ;; dashboard.export.options.merge.message - ;; dashboard.export.options.merge.title - [:h3 (tr (dm/str "dashboard.export.options." (d/name type) ".title"))] - [:p (tr (dm/str "dashboard.export.options." (d/name type) ".message"))] - [:input {:type "radio" - :checked (= selected type) - :data-type (name type) - :on-change on-change - :name "export-option"}] - [:span {:class "option-radio-check"}]]])] - - [:div.modal-footer - [:div.action-buttons - [:input.cancel-button - {:type "button" - :value (tr "labels.cancel") - :on-click on-cancel}] - - [:input.accept-button - {:class "primary" - :type "button" - :value (tr "labels.continue") - :on-click on-accept}]]]] - - (= status :exporting) - [:* - [:div.modal-content - (for [file (:files state)] - [:& export-entry {:file file :key (dm/str (:id file))}])] - - [:div.modal-footer - [:div.action-buttons - [:input.accept-button - {:class "primary" - :type "button" - :value (tr "labels.close") - :disabled (->> state :files (some :loading?)) - :on-click on-cancel}]]]])]]))) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:input {:class (stl/css :accept-btn) + :type "button" + :value (tr "labels.close") + :disabled (->> state :files (some :loading?)) + :on-click on-cancel}]]]])]])) diff --git a/frontend/src/app/main/ui/dashboard/export.scss b/frontend/src/app/main/ui/dashboard/export.scss index 6d092f1679..98c9fd2516 100644 --- a/frontend/src/app/main/ui/dashboard/export.scss +++ b/frontend/src/app/main/ui/dashboard/export.scss @@ -8,59 +8,64 @@ .modal-overlay { @extend .modal-overlay-base; +} - .modal-container { - @extend .modal-container-base; - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } +.modal-container { + @extend .modal-container-base; +} - .modal-content { - @include titleTipography; - margin-bottom: $s-24; - .export-option { - @extend .input-checkbox; - width: 100%; - align-items: flex-start; - label { - align-items: flex-start; - .modal-subtitle { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - } - span { - margin-top: $s-8; - } - .option-content { - @include flexColumn; - @include titleTipography; - } - } - } +.modal-header { + margin-bottom: $s-24; +} - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-btn { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + margin-bottom: $s-24; +} + +.export-option { + @extend .input-checkbox; + width: 100%; + align-items: flex-start; + label { + align-items: flex-start; + .modal-subtitle { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); } } + span { + margin-top: $s-8; + } +} + +.option-content { + @include flexColumn; + @include titleTipography; +} + +.action-buttons { + @extend .modal-action-btns; +} + +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; + } } .modal-scd-msg, diff --git a/frontend/src/app/main/ui/dashboard/import.cljs b/frontend/src/app/main/ui/dashboard/import.cljs index d0d4b4d2c5..2ac73e4214 100644 --- a/frontend/src/app/main/ui/dashboard/import.cljs +++ b/frontend/src/app/main/ui/dashboard/import.cljs @@ -18,7 +18,6 @@ [app.main.features :as features] [app.main.store :as st] [app.main.ui.components.file-uploader :refer [file-uploader]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.worker :as uw] [app.util.dom :as dom] @@ -152,8 +151,7 @@ (mf/defc import-entry [{:keys [state file editing? can-be-deleted?]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - loading? (or (= :analyzing (:status file)) + (let [loading? (or (= :analyzing (:status file)) (= :importing (:status file))) analyze-error? (= :analyze-error (:status file)) import-finish? (= :import-finish (:status file)) @@ -191,122 +189,66 @@ (fn [] (swap! state update :files remove-file (:file-id file))))] - (if new-css-system - [:div {:class (stl/css-case :file-entry true - :loading loading? - :success (and import-finish? (not import-warn?) (not import-error?)) - :warning (and import-finish? import-warn? (not import-error?)) - :error (or import-error? analyze-error?) - :editable (and ready? (not editing?)))} + [:div {:class (stl/css-case :file-entry true + :loading loading? + :success (and import-finish? (not import-warn?) (not import-error?)) + :warning (and import-finish? import-warn? (not import-error?)) + :error (or import-error? analyze-error?) + :editable (and ready? (not editing?)))} - [:div {:class (stl/css :file-name)} - [:div {:class (stl/css-case :file-icon true - :icon-fill ready?)} - (cond loading? i/loader-pencil - ready? i/logo-icon - import-warn? i/msg-warning - import-error? i/close-refactor - import-finish? i/tick-refactor - analyze-error? i/close-refactor)] + [:div {:class (stl/css :file-name)} + [:div {:class (stl/css-case :file-icon true + :icon-fill ready?)} + (cond loading? i/loader-pencil + ready? i/logo-icon + import-warn? i/msg-warning + import-error? i/close-refactor + import-finish? i/tick-refactor + analyze-error? i/close-refactor)] - (if editing? - [:div {:class (stl/css :file-name-edit)} - [:input {:type "text" - :auto-focus true - :default-value (:name file) - :on-key-press handle-edit-key-press - :on-blur handle-edit-blur}]] + (if editing? + [:div {:class (stl/css :file-name-edit)} + [:input {:type "text" + :auto-focus true + :default-value (:name file) + :on-key-press handle-edit-key-press + :on-blur handle-edit-blur}]] - [:div {:class (stl/css :file-name-label)} - (:name file) - (when is-shared? i/library-refactor)]) + [:div {:class (stl/css :file-name-label)} + (:name file) + (when is-shared? i/library-refactor)]) - [:div {:class (stl/css :edit-entry-buttons)} - (when (= "application/zip" (:type file)) - [:button {:on-click handle-edit-entry} i/curve-refactor]) - (when can-be-deleted? - [:button {:on-click handle-remove-entry} i/delete-refactor])]] - (cond - analyze-error? - [:div {:class (stl/css :error-message)} - (tr "dashboard.import.analyze-error")] + [:div {:class (stl/css :edit-entry-buttons)} + (when (= "application/zip" (:type file)) + [:button {:on-click handle-edit-entry} i/curve-refactor]) + (when can-be-deleted? + [:button {:on-click handle-remove-entry} i/delete-refactor])]] + (cond + analyze-error? + [:div {:class (stl/css :error-message)} + (tr "dashboard.import.analyze-error")] - import-error? - [:div {:class (stl/css :error-message)} - (tr "dashboard.import.import-error")] + import-error? + [:div {:class (stl/css :error-message)} + (tr "dashboard.import.import-error")] - (and (not import-finish?) (some? progress)) - [:div {:class (stl/css :progress-message)} (parse-progress-message progress)]) + (and (not import-finish?) (some? progress)) + [:div {:class (stl/css :progress-message)} (parse-progress-message progress)]) - [:div {:class (stl/css :linked-libraries)} - (for [library-id (:libraries file)] - (let [library-data (->> @state :files (d/seek #(= library-id (:file-id %)))) - error? (or (:deleted? library-data) (:import-error library-data))] - (when (some? library-data) - [:div {:class (stl/css-case :linked-library-tag true - :error error?)} - i/detach-refactor (:name library-data)])))]] - - - [:div.file-entry - {:class (dom/classnames - :loading loading? - :success (and import-finish? (not import-warn?) (not import-error?)) - :warning (and import-finish? import-warn? (not import-error?)) - :error (or import-error? analyze-error?) - :editable (and ready? (not editing?)))} - - [:div.file-name - [:div.file-icon - (cond loading? i/loader-pencil - ready? i/logo-icon - import-warn? i/msg-warning - import-error? i/close - import-finish? i/tick - analyze-error? i/close)] - - (if editing? - [:div.file-name-edit - [:input {:type "text" - :auto-focus true - :default-value (:name file) - :on-key-press handle-edit-key-press - :on-blur handle-edit-blur}]] - - [:div.file-name-label (:name file) (when is-shared? i/library)]) - - [:div.edit-entry-buttons - (when (= "application/zip" (:type file)) - [:button {:on-click handle-edit-entry} i/pencil]) - (when can-be-deleted? - [:button {:on-click handle-remove-entry} i/trash])]] - - (cond - analyze-error? - [:div.error-message - (tr "dashboard.import.analyze-error")] - - import-error? - [:div.error-message - (tr "dashboard.import.import-error")] - - (and (not import-finish?) (some? progress)) - [:div.progress-message (parse-progress-message progress)]) - - [:div.linked-libraries - (for [library-id (:libraries file)] - (let [library-data (->> @state :files (d/seek #(= library-id (:file-id %)))) - error? (or (:deleted? library-data) (:import-error library-data))] - (when (some? library-data) - [:div.linked-library-tag {:class (when error? "error")} - (if error? i/unchain i/chain) (:name library-data)])))]]))) + [:div {:class (stl/css :linked-libraries)} + (for [library-id (:libraries file)] + (let [library-data (->> @state :files (d/seek #(= library-id (:file-id %)))) + error? (or (:deleted? library-data) (:import-error library-data))] + (when (some? library-data) + [:div {:class (stl/css-case :linked-library-tag true + :error error?)} + i/detach-refactor (:name library-data)])))]])) (mf/defc import-dialog {::mf/register modal/components ::mf/register-as :import} [{:keys [project-id files template on-finish-import]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - state (mf/use-state + (let [state (mf/use-state {:status :analyzing :editing nil :importing-templates 0 @@ -425,122 +367,60 @@ #(doseq [file files] (wapi/revoke-uri (:uri file))))) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} (tr "dashboard.import")] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} (tr "dashboard.import")] - [:button {:class (stl/css :modal-close-btn) - :on-click handle-cancel} i/close-refactor]] + [:button {:class (stl/css :modal-close-btn) + :on-click handle-cancel} i/close-refactor]] - [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-content)} - (when (and (= :importing (:status @state)) (not pending-import?)) - (if (> warning-files 0) - [:div {:class (stl/css-case :feedback-banner true - :warning true)} - [:div {:class (stl/css :icon)} i/msg-warning-refactor] - [:div {:class (stl/css :message)} (tr "dashboard.import.import-warning" warning-files success-files)]] + (when (and (= :importing (:status @state)) (not pending-import?)) + (if (> warning-files 0) + [:div {:class (stl/css-case :feedback-banner true + :warning true)} + [:div {:class (stl/css :icon)} i/msg-warning-refactor] + [:div {:class (stl/css :message)} (tr "dashboard.import.import-warning" warning-files success-files)]] - [:div {:class (stl/css :feedback-banner)} - [:div {:class (stl/css :icon)} i/msg-success-refactor] - [:div {:class (stl/css :message)} (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]])) + [:div {:class (stl/css :feedback-banner)} + [:div {:class (stl/css :icon)} i/msg-success-refactor] + [:div {:class (stl/css :message)} (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]])) - (for [file files] - (let [editing? (and (some? (:file-id file)) - (= (:file-id file) (:editing @state)))] - [:& import-entry {:state state - :key (dm/str (:uri file)) - :file file - :editing? editing? - :can-be-deleted? (> (count files) 1)}])) - - (when (some? template) + (for [file files] + (let [editing? (and (some? (:file-id file)) + (= (:file-id file) (:editing @state)))] [:& import-entry {:state state - :file (assoc template :status (if (= 1 (:importing-templates @state)) :importing :ready)) - :editing? false - :can-be-deleted? false}])] + :key (dm/str (:uri file)) + :file file + :editing? editing? + :can-be-deleted? (> (count files) 1)}])) - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - (when (= :analyzing (:status @state)) - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.cancel") - :on-click handle-cancel}]) + (when (some? template) + [:& import-entry {:state state + :file (assoc template :status (if (= 1 (:importing-templates @state)) :importing :ready)) + :editing? false + :can-be-deleted? false}])] - (when (= :analyzing (:status @state)) - [:input {:class (stl/css :accept-btn) - :type "button" - :value (tr "labels.continue") - :disabled (or pending-analysis? (not valid-files?)) - :on-click handle-continue}]) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + (when (= :analyzing (:status @state)) + [:input {:class (stl/css :cancel-button) + :type "button" + :value (tr "labels.cancel") + :on-click handle-cancel}]) - (when (= :importing (:status @state)) - [:input {:class (stl/css :accept-btn) - :type "button" - :value (tr "labels.accept") - :disabled (or pending-import? (not valid-files?)) - :on-click handle-accept}])]]]] + (when (= :analyzing (:status @state)) + [:input {:class (stl/css :accept-btn) + :type "button" + :value (tr "labels.continue") + :disabled (or pending-analysis? (not valid-files?)) + :on-click handle-continue}]) - - - [:div.modal-overlay - [:div.modal-container.import-dialog - [:div.modal-header - [:div.modal-header-title - [:h2 (tr "dashboard.import")]] - - [:div.modal-close-button - {:on-click handle-cancel} i/close]] - - [:div.modal-content - (when (and (= :importing (:status @state)) (not pending-import?)) - (if (> warning-files 0) - [:div.feedback-banner.warning - [:div.icon i/msg-warning] - [:div.message (tr "dashboard.import.import-warning" warning-files success-files)]] - - [:div.feedback-banner - [:div.icon i/checkbox-checked] - [:div.message (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]])) - - (for [file files] - (let [editing? (and (some? (:file-id file)) - (= (:file-id file) (:editing @state)))] - [:& import-entry {:state state - :key (dm/str (:uri file)) - :file file - :editing? editing? - :can-be-deleted? (> (count files) 1)}])) - - (when (some? template) - [:& import-entry {:state state - :file (assoc template :status (if (= 1 (:importing-templates @state)) :importing :ready)) - :editing? false - :can-be-deleted? false}])] - - [:div.modal-footer - [:div.action-buttons - (when (= :analyzing (:status @state)) - [:input.cancel-button - {:type "button" - :value (tr "labels.cancel") - :on-click handle-cancel}]) - - (when (= :analyzing (:status @state)) - [:input.accept-button - {:class "primary" - :type "button" - :value (tr "labels.continue") - :disabled (or pending-analysis? (not valid-files?)) - :on-click handle-continue}]) - - (when (= :importing (:status @state)) - [:input.accept-button - {:class "primary" - :type "button" - :value (tr "labels.accept") - :disabled (or pending-import? (not valid-files?)) - :on-click handle-accept}])]]]]))) + (when (= :importing (:status @state)) + [:input {:class (stl/css :accept-btn) + :type "button" + :value (tr "labels.accept") + :disabled (or pending-import? (not valid-files?)) + :on-click handle-accept}])]]]])) diff --git a/frontend/src/app/main/ui/dashboard/import.scss b/frontend/src/app/main/ui/dashboard/import.scss index 3ed738462e..4221530e0d 100644 --- a/frontend/src/app/main/ui/dashboard/import.scss +++ b/frontend/src/app/main/ui/dashboard/import.scss @@ -8,69 +8,72 @@ .modal-overlay { @extend .modal-overlay-base; +} - .modal-container { - @extend .modal-container-base; - border: $s-1 solid var(--modal-border-color); - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } +.modal-container { + @extend .modal-container-base; + border: $s-1 solid var(--modal-border-color); +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + margin-bottom: $s-24; +} + +.feedback-banner { + @include flexRow; + height: $s-32; + width: 100%; + margin-bottom: $s-24; + border-radius: $br-8; + background-color: var(--alert-background-color-ok); + color: var(--alert-foreground-color-ok); + + .icon { + @include flexCenter; + height: $s-24; + width: $s-24; + svg { + @extend .button-icon; + stroke: var(--alert-foreground-color-ok); } - - .modal-content { - @include titleTipography; - margin-bottom: $s-24; - .feedback-banner { - @include flexRow; - height: $s-32; - width: 100%; - margin-bottom: $s-24; - border-radius: $br-8; - background-color: var(--alert-background-color-ok); - color: var(--alert-foreground-color-ok); - - .icon { - @include flexCenter; - height: $s-24; - width: $s-24; - svg { - @extend .button-icon; - stroke: var(--alert-foreground-color-ok); - } - } - .message { - @include titleTipography; - } - &.warning { - background-color: var(--alert-background-color-warning); - color: var(--alert-foreground-color-warning); - .icon svg { - stroke: var(--alert-foreground-color-warning); - } - } - } + } + .message { + @include titleTipography; + } + &.warning { + background-color: var(--alert-background-color-warning); + color: var(--alert-foreground-color-warning); + .icon svg { + stroke: var(--alert-foreground-color-warning); } + } +} - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-btn { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } - } +.action-buttons { + @extend .modal-action-btns; +} + +.cancel-button { + @extend .modal-cancel-btn; +} +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; } } @@ -122,6 +125,7 @@ .error-message, .progress-message { height: $s-32; + color: var(--modal-text-foreground-color); } .linked-libraries { diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs index 2f4f57a65d..8a2f958a3b 100644 --- a/frontend/src/app/main/ui/dashboard/team.cljs +++ b/frontend/src/app/main/ui/dashboard/team.cljs @@ -21,7 +21,6 @@ [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.change-owner] [app.main.ui.dashboard.team-form] [app.main.ui.icons :as i] @@ -36,8 +35,7 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [{:keys [section team]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-nav-members (mf/use-fn #(st/emit! (dd/go-to-team-members))) + (let [on-nav-members (mf/use-fn #(st/emit! (dd/go-to-team-members))) on-nav-settings (mf/use-fn #(st/emit! (dd/go-to-team-settings))) on-nav-invitations (mf/use-fn #(st/emit! (dd/go-to-team-invitations))) on-nav-webhooks (mf/use-fn #(st/emit! (dd/go-to-team-webhooks))) @@ -56,62 +54,33 @@ :team team :origin :team}))))] - (if new-css-system - [:header {:class (stl/css :dashboard-header :team)} - [:div {:class (stl/css :dashboard-title)} - [:h1 (cond - members-section? (tr "labels.members") - settings-section? (tr "labels.settings") - invitations-section? (tr "labels.invitations") - webhooks-section? (tr "labels.webhooks") - :else nil)]] - [:nav {:class (stl/css :dashboard-header-menu)} - [:ul {:class (stl/css :dashboard-header-options)} - [:li {:class (when members-section? (stl/css :active))} - [:a {:on-click on-nav-members} (tr "labels.members")]] - [:li {:class (when invitations-section? (stl/css :active))} - [:a {:on-click on-nav-invitations} (tr "labels.invitations")]] - (when (contains? cfg/flags :webhooks) - [:li {:class (when webhooks-section? (stl/css :active))} - [:a {:on-click on-nav-webhooks} (tr "labels.webhooks")]]) - [:li {:class (when settings-section? (stl/css :active))} - [:a {:on-click on-nav-settings} (tr "labels.settings")]]]] - [:div {:class (stl/css :dashboard-buttons)} - (if (and (or invitations-section? members-section?) (:is-admin permissions)) - [:a - {:class (stl/css :btn-secondary :btn-small) - :on-click on-invite-member - :data-test "invite-member"} - (tr "dashboard.invite-profile")] - [:div {:class (stl/css :blank-space)}])]] - - ;; OLD - [:header.dashboard-header.team - [:div.dashboard-title - [:h1 (cond - members-section? (tr "labels.members") - settings-section? (tr "labels.settings") - invitations-section? (tr "labels.invitations") - webhooks-section? (tr "labels.webhooks") - :else nil)]] - [:nav.dashboard-header-menu - [:ul.dashboard-header-options - [:li {:class (when members-section? "active")} - [:a {:on-click on-nav-members} (tr "labels.members")]] - [:li {:class (when invitations-section? "active")} - [:a {:on-click on-nav-invitations} (tr "labels.invitations")]] - (when (contains? cfg/flags :webhooks) - [:li {:class (when webhooks-section? "active")} - [:a {:on-click on-nav-webhooks} (tr "labels.webhooks")]]) - [:li {:class (when settings-section? "active")} - [:a {:on-click on-nav-settings} (tr "labels.settings")]]]] - [:div.dashboard-buttons - (if (and (or invitations-section? members-section?) (:is-admin permissions)) - [:a.btn-secondary.btn-small - {:on-click on-invite-member - :data-test "invite-member"} - (tr "dashboard.invite-profile")] - [:div.blank-space])]]))) + [:header {:class (stl/css :dashboard-header :team)} + [:div {:class (stl/css :dashboard-title)} + [:h1 (cond + members-section? (tr "labels.members") + settings-section? (tr "labels.settings") + invitations-section? (tr "labels.invitations") + webhooks-section? (tr "labels.webhooks") + :else nil)]] + [:nav {:class (stl/css :dashboard-header-menu)} + [:ul {:class (stl/css :dashboard-header-options)} + [:li {:class (when members-section? (stl/css :active))} + [:a {:on-click on-nav-members} (tr "labels.members")]] + [:li {:class (when invitations-section? (stl/css :active))} + [:a {:on-click on-nav-invitations} (tr "labels.invitations")]] + (when (contains? cfg/flags :webhooks) + [:li {:class (when webhooks-section? (stl/css :active))} + [:a {:on-click on-nav-webhooks} (tr "labels.webhooks")]]) + [:li {:class (when settings-section? (stl/css :active))} + [:a {:on-click on-nav-settings} (tr "labels.settings")]]]] + [:div {:class (stl/css :dashboard-buttons)} + (if (and (or invitations-section? members-section?) (:is-admin permissions)) + [:a + {:class (stl/css :btn-secondary :btn-small) + :on-click on-invite-member + :data-test "invite-member"} + (tr "dashboard.invite-profile")] + [:div {:class (stl/css :blank-space)}])]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; INVITATIONS MODAL @@ -140,8 +109,7 @@ ::mf/register-as :invite-members ::mf/wrap-props false} [{:keys [team origin]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - members-map (mf/deref refs/dashboard-team-members) + (let [members-map (mf/deref refs/dashboard-team-members) perms (:permissions team) roles (mf/use-memo (mf/deps perms) #(get-available-roles perms)) @@ -188,80 +156,41 @@ (dd/fetch-team-invitations))))] - (if new-css-system - [:div {:class (stl/css-case :modal-team-container true - :hero (= origin :hero))} - [:& fm/form {:on-submit on-submit :form form} - [:div {:class (stl/css :modal-title)} - (tr "modals.invite-team-member.title")] + [:div {:class (stl/css-case :modal-team-container true + :hero (= origin :hero))} + [:& fm/form {:on-submit on-submit :form form} + [:div {:class (stl/css :modal-title)} + (tr "modals.invite-team-member.title")] - (when-not (= "" @error-text) - [:div {:class (stl/css :error-msg)} - [:span {:class (stl/css :icon)} i/msg-error] - [:span {:class (stl/css :message)} @error-text]]) + (when-not (= "" @error-text) + [:div {:class (stl/css :error-msg)} + [:span {:class (stl/css :icon)} i/msg-error] + [:span {:class (stl/css :message)} @error-text]]) - (when (some current-data-emails current-members-emails) - [:div {:class (stl/css :warning-msg)} - [:span {:class (stl/css :icon)} i/msg-warning] - [:span {:class (stl/css :message)} (tr "modals.invite-member.repeated-invitation")]]) + (when (some current-data-emails current-members-emails) + [:div {:class (stl/css :warning-msg)} + [:span {:class (stl/css :icon)} i/msg-warning] + [:span {:class (stl/css :message)} (tr "modals.invite-member.repeated-invitation")]]) - [:div {:class (stl/css :role-select)} - [:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")] - [:& fm/select {:name :role :options roles}]] + [:div {:class (stl/css :role-select)} + [:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")] + [:& fm/select {:name :role :options roles}]] - [:div {:class (stl/css :invitation-row)} - [:& fm/multi-input {:type "email" - :name :emails - :auto-focus? true - :trim true - :valid-item-fn us/parse-email - :caution-item-fn current-members-emails - :label (tr "modals.invite-member.emails") - :on-submit on-submit}]] + [:div {:class (stl/css :invitation-row)} + [:& fm/multi-input {:type "email" + :name :emails + :auto-focus? true + :trim true + :valid-item-fn us/parse-email + :caution-item-fn current-members-emails + :label (tr "modals.invite-member.emails") + :on-submit on-submit}]] - [:div {:class (stl/css :action-buttons)} - [:> fm/submit-button* - {:label (tr "modals.invite-member-confirm.accept") - :disabled (and (boolean (some current-data-emails current-members-emails)) - (empty? (remove current-members-emails current-data-emails)))}]]]] - - - [:div.modal.dashboard-invite-modal.form-container - {:class (dom/classnames - :hero (= origin :hero))} - [:& fm/form {:on-submit on-submit :form form} - [:div.title - [:span.text (tr "modals.invite-team-member.title")]] - - (when-not (= "" @error-text) - [:div.error - [:span.icon i/msg-error] - [:span.text @error-text]]) - - (when (some current-data-emails current-members-emails) - [:div.warning - [:span.icon i/msg-warning] - [:span.text (tr "modals.invite-member.repeated-invitation")]]) - - [:div.form-row - [:p.label (tr "onboarding.choice.team-up.roles")] - [:& fm/select {:name :role :options roles}]] - - [:div.form-row - [:& fm/multi-input {:type "email" - :name :emails - :auto-focus? true - :trim true - :valid-item-fn us/parse-email - :caution-item-fn current-members-emails - :label (tr "modals.invite-member.emails") - :on-submit on-submit}]] - - [:div.action-buttons - [:> fm/submit-button* - {:label (tr "modals.invite-member-confirm.accept") - :disabled (and (boolean (some current-data-emails current-members-emails)) - (empty? (remove current-members-emails current-data-emails)))}]]]]))) + [:div {:class (stl/css :action-buttons)} + [:> fm/submit-button* + {:label (tr "modals.invite-member-confirm.accept") + :disabled (and (boolean (some current-data-emails current-members-emails)) + (empty? (remove current-members-emails current-data-emails)))}]]]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; MEMBERS SECTION @@ -270,33 +199,20 @@ (mf/defc member-info {::mf/wrap-props false} [{:keys [member profile]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - is-you? (= (:id profile) (:id member))] - (if new-css-system - [:* - [:div {:class (stl/css :member-image)} - [:img {:src (cfg/resolve-profile-photo-url member)}]] - [:div {:class (stl/css :member-info)} - [:div {:class (stl/css :member-name)} (:name member) - (when is-you? - [:span {:class (stl/css :you)} (tr "labels.you")])] - [:div {:class (stl/css :member-email)} (:email member)]]] - - ;; OLD - [:* - [:div.member-image - [:img {:src (cfg/resolve-profile-photo-url member)}]] - [:div.member-info - [:div.member-name (:name member) - (when is-you? - [:span.you (tr "labels.you")])] - [:div.member-email (:email member)]]]))) + (let [is-you? (= (:id profile) (:id member))] + [:* + [:div {:class (stl/css :member-image)} + [:img {:src (cfg/resolve-profile-photo-url member)}]] + [:div {:class (stl/css :member-info)} + [:div {:class (stl/css :member-name)} (:name member) + (when is-you? + [:span {:class (stl/css :you)} (tr "labels.you")])] + [:div {:class (stl/css :member-email)} (:email member)]]])) (mf/defc rol-info {::mf/wrap-props false} [{:keys [member team on-set-admin on-set-editor on-set-owner profile]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - member-is-owner? (:is-owner member) + (let [member-is-owner? (:is-owner member) member-is-admin? (and (:is-admin member) (not member-is-owner?)) member-is-editor? (and (:can-edit member) (and (not member-is-admin?) (not member-is-owner?))) show? (mf/use-state false) @@ -316,50 +232,29 @@ on-show (mf/use-fn #(reset! show? true)) on-hide (mf/use-fn #(reset! show? false))] - (if new-css-system - [:* - (if (and can-change-rol? not-superior? (not (and is-you? you-owner?))) - [:div {:class (stl/css :rol-selector :has-priv) - :on-click on-show} - [:span {:class (stl/css :rol-label)} (tr role)] - [:span {:class (stl/css :icon)} i/arrow-down]] - [:div {:class (stl/css :rol-selector)} - [:span {:class (stl/css :rol-label)} (tr role)]]) + [:* + (if (and can-change-rol? not-superior? (not (and is-you? you-owner?))) + [:div {:class (stl/css :rol-selector :has-priv) + :on-click on-show} + [:span {:class (stl/css :rol-label)} (tr role)] + [:span {:class (stl/css :icon)} i/arrow-down]] + [:div {:class (stl/css :rol-selector)} + [:span {:class (stl/css :rol-label)} (tr role)]]) - [:& dropdown {:show @show? :on-close on-hide} - [:ul {:class (stl/css :dropdown :options-dropdown)} - [:li {:on-click on-set-admin} (tr "labels.admin")] - [:li {:on-click on-set-editor} (tr "labels.editor")] - ;; Temporarily disabled viewer role - ;; https://tree.taiga.io/project/penpot/issue/1083 - ;; [:li {:on-click set-viewer} (tr "labels.viewer")] - (when you-owner? - [:li {:on-click (partial on-set-owner member)} (tr "labels.owner")])]]] - - ;; OLD - [:* - (if (and can-change-rol? not-superior? (not (and is-you? you-owner?))) - [:div.rol-selector.has-priv {:on-click on-show} - [:span.rol-label (tr role)] - [:span.icon i/arrow-down]] - [:div.rol-selector - [:span.rol-label (tr role)]]) - - [:& dropdown {:show @show? :on-close on-hide} - [:ul.dropdown.options-dropdown - [:li {:on-click on-set-admin} (tr "labels.admin")] - [:li {:on-click on-set-editor} (tr "labels.editor")] - ;; Temporarily disabled viewer role - ;; https://tree.taiga.io/project/penpot/issue/1083 - ;; [:li {:on-click set-viewer} (tr "labels.viewer")] - (when you-owner? - [:li {:on-click (partial on-set-owner member)} (tr "labels.owner")])]]]))) + [:& dropdown {:show @show? :on-close on-hide} + [:ul {:class (stl/css :dropdown :options-dropdown)} + [:li {:on-click on-set-admin} (tr "labels.admin")] + [:li {:on-click on-set-editor} (tr "labels.editor")] + ;; Temporarily disabled viewer role + ;; https://tree.taiga.io/project/penpot/issue/1083 + ;; [:li {:on-click set-viewer} (tr "labels.viewer")] + (when you-owner? + [:li {:on-click (partial on-set-owner member)} (tr "labels.owner")])]]])) (mf/defc member-actions {::mf/wrap-props false} [{:keys [member team on-delete on-leave profile]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - is-owner? (:is-owner member) + (let [is-owner? (:is-owner member) owner? (dm/get-in team [:permissions :is-owner]) admin? (dm/get-in team [:permissions :is-admin]) show? (mf/use-state false) @@ -369,30 +264,17 @@ on-show (mf/use-fn #(reset! show? true)) on-hide (mf/use-fn #(reset! show? false))] - (if new-css-system - [:* - (when (or is-you? (and can-delete? (not (and is-owner? (not owner?))))) - [:span {:class (stl/css :icon) - :on-click on-show} [i/actions]]) + [:* + (when (or is-you? (and can-delete? (not (and is-owner? (not owner?))))) + [:span {:class (stl/css :icon) + :on-click on-show} [i/actions]]) - [:& dropdown {:show @show? :on-close on-hide} - [:ul {:class (stl/css :dropdown :actions-dropdown)} - (when is-you? - [:li {:on-click on-leave} (tr "dashboard.leave-team")]) - (when (and can-delete? (not is-you?) (not (and is-owner? (not owner?)))) - [:li {:on-click on-delete} (tr "labels.remove-member")])]]] - - ;; OLD - [:* - (when (or is-you? (and can-delete? (not (and is-owner? (not owner?))))) - [:span.icon {:on-click on-show} [i/actions]]) - - [:& dropdown {:show @show? :on-close on-hide} - [:ul.dropdown.actions-dropdown - (when is-you? - [:li {:on-click on-leave} (tr "dashboard.leave-team")]) - (when (and can-delete? (not is-you?) (not (and is-owner? (not owner?)))) - [:li {:on-click on-delete} (tr "labels.remove-member")])]]]))) + [:& dropdown {:show @show? :on-close on-hide} + [:ul {:class (stl/css :dropdown :actions-dropdown)} + (when is-you? + [:li {:on-click on-leave} (tr "dashboard.leave-team")]) + (when (and can-delete? (not is-you?) (not (and is-owner? (not owner?)))) + [:li {:on-click on-delete} (tr "labels.remove-member")])]]])) (defn- set-role! [member-id role] (let [params {:member-id member-id :role role}] @@ -403,8 +285,7 @@ ::mf/wrap-props false} [{:keys [team member members profile]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - member-id (:id member) + (let [member-id (:id member) on-set-admin (mf/use-fn (mf/deps member-id) (partial set-role! member-id :admin)) on-set-editor (mf/use-fn (mf/deps member-id) (partial set-role! member-id :editor)) owner? (dm/get-in team [:permissions :is-owner]) @@ -513,50 +394,29 @@ (= true owner?) on-change-owner-and-leave :else on-leave)] - (if new-css-system - [:div {:class (stl/css :table-row)} - [:div {:class (stl/css :table-field :name)} - [:& member-info {:member member :profile profile}]] + [:div {:class (stl/css :table-row)} + [:div {:class (stl/css :table-field :name)} + [:& member-info {:member member :profile profile}]] - [:div {:class (stl/css :table-field :roles)} - [:& rol-info {:member member - :team team - :on-set-admin on-set-admin - :on-set-editor on-set-editor - :on-set-owner on-set-owner - :profile profile}]] + [:div {:class (stl/css :table-field :roles)} + [:& rol-info {:member member + :team team + :on-set-admin on-set-admin + :on-set-editor on-set-editor + :on-set-owner on-set-owner + :profile profile}]] - [:div {:class (stl/css :table-field :actions)} - [:& member-actions {:member member - :profile profile - :team team - :on-delete on-delete - :on-leave on-leave'}]]] - ;; OLD - [:div.table-row - [:div.table-field.name - [:& member-info {:member member :profile profile}]] - - [:div.table-field.roles - [:& rol-info {:member member - :team team - :on-set-admin on-set-admin - :on-set-editor on-set-editor - :on-set-owner on-set-owner - :profile profile}]] - - [:div.table-field.actions - [:& member-actions {:member member - :profile profile - :team team - :on-delete on-delete - :on-leave on-leave'}]]]))) + [:div {:class (stl/css :table-field :actions)} + [:& member-actions {:member member + :profile profile + :team team + :on-delete on-delete + :on-leave on-leave'}]]])) (mf/defc team-members {::mf/wrap-props false} [{:keys [members-map team profile]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - members (mf/with-memo [members-map] + (let [members (mf/with-memo [members-map] (->> (vals members-map) (sort-by :created-at) (remove :is-owner))) @@ -564,53 +424,30 @@ (->> (vals members-map) (d/seek :is-owner)))] - (if new-css-system - [:div {:class (stl/css :dashboard-table :team-members)} - [:div {:class (stl/css :table-header)} - [:div {:class (stl/css :table-field :name)} (tr "labels.member")] - [:div {:class (stl/css :table-field :role)} (tr "labels.role")]] + [:div {:class (stl/css :dashboard-table :team-members)} + [:div {:class (stl/css :table-header)} + [:div {:class (stl/css :table-field :name)} (tr "labels.member")] + [:div {:class (stl/css :table-field :role)} (tr "labels.role")]] - [:div {:class (stl/css :table-rows)} + [:div {:class (stl/css :table-rows)} + [:& team-member + {:member owner + :team team + :profile profile + :members members-map}] + + (for [item members] [:& team-member - {:member owner + {:member item :team team :profile profile - :members members-map}] - - (for [item members] - [:& team-member - {:member item - :team team - :profile profile - :key (:id item) - :members members-map}])]] - - ;; OLD - [:div.dashboard-table.team-members - [:div.table-header - [:div.table-field.name (tr "labels.member")] - [:div.table-field.role (tr "labels.role")]] - - [:div.table-rows - [:& team-member - {:member owner - :team team - :profile profile - :members members-map}] - - (for [item members] - [:& team-member - {:member item - :team team - :profile profile - :key (:id item) - :members members-map}])]]))) + :key (:id item) + :members members-map}])]])) (mf/defc team-members-page {::mf/wrap-props false} [{:keys [team profile]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - members-map (mf/deref refs/dashboard-team-members)] + (let [members-map (mf/deref refs/dashboard-team-members)] (mf/with-effect [team] (dom/set-html-title @@ -622,23 +459,13 @@ (mf/with-effect [team] (st/emit! (dd/fetch-team-members (:id team)))) - (if new-css-system - [:* - [:& header {:section :dashboard-team-members :team team}] - [:section {:class (stl/css :dashboard-container :dashboard-team-members)} - [:& team-members - {:profile profile - :team team - :members-map members-map}]]] - - ;; OLD - [:* - [:& header {:section :dashboard-team-members :team team}] - [:section.dashboard-container.dashboard-team-members - [:& team-members - {:profile profile - :team team - :members-map members-map}]]]))) + [:* + [:& header {:section :dashboard-team-members :team team}] + [:section {:class (stl/css :dashboard-container :dashboard-team-members)} + [:& team-members + {:profile profile + :team team + :members-map members-map}]]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; INVITATIONS SECTION @@ -647,8 +474,7 @@ (mf/defc invitation-role-selector {::mf/wrap-props false} [{:keys [can-invite? role status on-change]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - show? (mf/use-state false) + (let [show? (mf/use-state false) label (cond (= role :owner) (tr "labels.owner") (= role :admin) (tr "labels.admin") @@ -667,65 +493,37 @@ (keyword))] (on-change role event))))] - (if new-css-system - [:* - (if (and can-invite? (= status :pending)) - [:div {:class (stl/css :rol-selector :has-priv) - :on-click on-show} - [:span {:class (stl/css :rol-label)} label] - [:span {:class (stl/css :icon)} i/arrow-down]] - [:div {:class (stl/css :rol-selector)} - [:span {:class (stl/css :rol-label)} label]]) + [:* + (if (and can-invite? (= status :pending)) + [:div {:class (stl/css :rol-selector :has-priv) + :on-click on-show} + [:span {:class (stl/css :rol-label)} label] + [:span {:class (stl/css :icon)} i/arrow-down]] + [:div {:class (stl/css :rol-selector)} + [:span {:class (stl/css :rol-label)} label]]) - [:& dropdown {:show @show? :on-close on-hide} - [:ul {:class (stl/css :dropdown :options-dropdown)} - [:li {:data-role "admin" :on-click on-change'} (tr "labels.admin")] - [:li {:data-role "editor" :on-click on-change'} (tr "labels.editor")]]]] - - ;; OLD - [:* - (if (and can-invite? (= status :pending)) - [:div.rol-selector.has-priv {:on-click on-show} - [:span.rol-label label] - [:span.icon i/arrow-down]] - [:div.rol-selector - [:span.rol-label label]]) - - [:& dropdown {:show @show? :on-close on-hide} - [:ul.dropdown.options-dropdown - [:li {:data-role "admin" :on-click on-change'} (tr "labels.admin")] - [:li {:data-role "editor" :on-click on-change'} (tr "labels.editor")]]]]))) + [:& dropdown {:show @show? :on-close on-hide} + [:ul {:class (stl/css :dropdown :options-dropdown)} + [:li {:data-role "admin" :on-click on-change'} (tr "labels.admin")] + [:li {:data-role "editor" :on-click on-change'} (tr "labels.editor")]]]])) (mf/defc invitation-status-badge {::mf/wrap-props false} [{:keys [status]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div - {:class (stl/css-case - :status-badge true - :expired (= status :expired) - :pending (= status :pending))} - [:span {:class (stl/css :status-label)} - (if (= status :expired) - (tr "labels.expired-invitation") - (tr "labels.pending-invitation"))]] - - ;; OLD - [:div.status-badge - {:class (dom/classnames - :expired (= status :expired) - :pending (= status :pending))} - [:span.status-label - (if (= status :expired) - (tr "labels.expired-invitation") - (tr "labels.pending-invitation"))]]))) + [:div + {:class (stl/css-case + :status-badge true + :expired (= status :expired) + :pending (= status :pending))} + [:span {:class (stl/css :status-label)} + (if (= status :expired) + (tr "labels.expired-invitation") + (tr "labels.pending-invitation"))]]) (mf/defc invitation-actions {::mf/wrap-props false} [{:keys [invitation team-id]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - show? (mf/use-state false) + (let [show? (mf/use-state false) email (:email invitation) role (:role invitation) @@ -800,32 +598,21 @@ on-hide (mf/use-fn #(reset! show? false)) on-show (mf/use-fn #(reset! show? true))] - (if new-css-system - [:* - [:span {:class (stl/css :icon) - :on-click on-show} [i/actions]] - [:& dropdown {:show @show? :on-close on-hide} - [:ul {:class (stl/css :dropdown :actions-dropdown)} - [:li {:on-click on-copy} (tr "labels.copy-invitation-link")] - [:li {:on-click on-resend} (tr "labels.resend-invitation")] - [:li {:on-click on-delete} (tr "labels.delete-invitation")]]]] - - ;; OLD - [:* - [:span.icon {:on-click on-show} [i/actions]] - [:& dropdown {:show @show? :on-close on-hide} - [:ul.dropdown.actions-dropdown - [:li {:on-click on-copy} (tr "labels.copy-invitation-link")] - [:li {:on-click on-resend} (tr "labels.resend-invitation")] - [:li {:on-click on-delete} (tr "labels.delete-invitation")]]]]))) + [:* + [:span {:class (stl/css :icon) + :on-click on-show} [i/actions]] + [:& dropdown {:show @show? :on-close on-hide} + [:ul {:class (stl/css :dropdown :actions-dropdown)} + [:li {:on-click on-copy} (tr "labels.copy-invitation-link")] + [:li {:on-click on-resend} (tr "labels.resend-invitation")] + [:li {:on-click on-delete} (tr "labels.delete-invitation")]]]])) (mf/defc invitation-row {::mf/wrap [mf/memo] ::mf/wrap-props false} [{:keys [invitation can-invite? team-id] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - expired? (:expired invitation) + (let [expired? (:expired invitation) email (:email invitation) role (:role invitation) status (if expired? :expired :pending) @@ -838,106 +625,58 @@ mdata {:on-success #(st/emit! (dd/fetch-team-invitations))}] (st/emit! (dd/update-team-invitation-role (with-meta params mdata))))))] - (if new-css-system - [:div {:class (stl/css :table-row)} - [:div {:class (stl/css :table-field :mail)} email] + [:div {:class (stl/css :table-row)} + [:div {:class (stl/css :table-field :mail)} email] - [:div {:class (stl/css :table-field :roles)} - [:& invitation-role-selector - {:can-invite? can-invite? - :role role - :status status - :on-change on-change-role}]] + [:div {:class (stl/css :table-field :roles)} + [:& invitation-role-selector + {:can-invite? can-invite? + :role role + :status status + :on-change on-change-role}]] - [:div {:class (stl/css :table-field :status)} - [:& invitation-status-badge {:status status}]] + [:div {:class (stl/css :table-field :status)} + [:& invitation-status-badge {:status status}]] - [:div {:class (stl/css :table-field :actions)} - (when can-invite? - [:& invitation-actions - {:invitation invitation - :team-id team-id}])]] - - ;; OLD - [:div.table-row - [:div.table-field.mail email] - - [:div.table-field.roles - [:& invitation-role-selector - {:can-invite? can-invite? - :role role - :status status - :on-change on-change-role}]] - - [:div.table-field.status - [:& invitation-status-badge {:status status}]] - - [:div.table-field.actions - (when can-invite? - [:& invitation-actions - {:invitation invitation - :team-id team-id}])]]))) + [:div {:class (stl/css :table-field :actions)} + (when can-invite? + [:& invitation-actions + {:invitation invitation + :team-id team-id}])]])) (mf/defc empty-invitation-table [{:keys [can-invite?] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :empty-invitations)} - [:span (tr "labels.no-invitations")] - (when can-invite? - [:& i18n/tr-html {:label "labels.no-invitations-hint" - :tag-name "span"}])] - ;; OLD - [:div.empty-invitations - [:span (tr "labels.no-invitations")] - (when can-invite? - [:& i18n/tr-html {:label "labels.no-invitations-hint" - :tag-name "span"}])]))) + [:div {:class (stl/css :empty-invitations)} + [:span (tr "labels.no-invitations")] + (when can-invite? + [:& i18n/tr-html {:label "labels.no-invitations-hint" + :tag-name "span"}])]) (mf/defc invitation-section [{:keys [team invitations] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - owner? (dm/get-in team [:permissions :is-owner]) + (let [owner? (dm/get-in team [:permissions :is-owner]) admin? (dm/get-in team [:permissions :is-admin]) can-invite? (or owner? admin?) team-id (:id team)] - (if new-css-system - [:div {:class (stl/css :dashboard-table :invitations)} - [:div {:class (stl/css :table-header)} - [:div {:class (stl/css :table-field :name)} (tr "labels.invitations")] - [:div {:class (stl/css :table-field :role)} (tr "labels.role")] - [:div {:class (stl/css :table-field :status)} (tr "labels.status")]] - (if (empty? invitations) - [:& empty-invitation-table {:can-invite? can-invite?}] - [:div {:class (stl/css :table-rows)} - (for [invitation invitations] - [:& invitation-row - {:key (:email invitation) - :invitation invitation - :can-invite? can-invite? - :team-id team-id}])])] - - ;; OLD - [:div.dashboard-table.invitations - [:div.table-header - [:div.table-field.name (tr "labels.invitations")] - [:div.table-field.role (tr "labels.role")] - [:div.table-field.status (tr "labels.status")]] - (if (empty? invitations) - [:& empty-invitation-table {:can-invite? can-invite?}] - [:div.table-rows - (for [invitation invitations] - [:& invitation-row - {:key (:email invitation) - :invitation invitation - :can-invite? can-invite? - :team-id team-id}])])]))) + [:div {:class (stl/css :dashboard-table :invitations)} + [:div {:class (stl/css :table-header)} + [:div {:class (stl/css :table-field :name)} (tr "labels.invitations")] + [:div {:class (stl/css :table-field :role)} (tr "labels.role")] + [:div {:class (stl/css :table-field :status)} (tr "labels.status")]] + (if (empty? invitations) + [:& empty-invitation-table {:can-invite? can-invite?}] + [:div {:class (stl/css :table-rows)} + (for [invitation invitations] + [:& invitation-row + {:key (:email invitation) + :invitation invitation + :can-invite? can-invite? + :team-id team-id}])])])) (mf/defc team-invitations-page [{:keys [team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - invitations (mf/deref refs/dashboard-team-invitations)] + (let [invitations (mf/deref refs/dashboard-team-invitations)] (mf/with-effect [team] (dom/set-html-title @@ -949,21 +688,12 @@ (mf/with-effect [] (st/emit! (dd/fetch-team-invitations))) - (if new-css-system - [:* - [:& header {:section :dashboard-team-invitations - :team team}] - [:section {:class (stl/css :dashboard-container :dashboard-team-invitations)} - [:& invitation-section {:team team - :invitations invitations}]]] - - ;; OLD - [:* - [:& header {:section :dashboard-team-invitations - :team team}] - [:section.dashboard-container.dashboard-team-invitations - [:& invitation-section {:team team - :invitations invitations}]]]))) + [:* + [:& header {:section :dashboard-team-invitations + :team team}] + [:section {:class (stl/css :dashboard-container :dashboard-team-invitations)} + [:& invitation-section {:team team + :invitations invitations}]]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; WEBHOOKS SECTION @@ -987,8 +717,7 @@ ::mf/register-as :webhook} [{:keys [webhook] :as props}] ;; FIXME: this is a workaround because input fields do not support rendering hooks - (let [new-css-system (mf/use-ctx ctx/new-css-system) - initial (mf/use-memo (fn [] (or (some-> webhook (update :uri str)) + (let [initial (mf/use-memo (fn [] (or (some-> webhook (update :uri str)) {:is-active false :mtype "application/json"}))) form (fm/use-form :spec ::webhook-form :initial initial @@ -1052,181 +781,95 @@ (on-create-submit form))))) on-modal-close #(st/emit! (modal/hide))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:& fm/form {:form form :on-submit on-submit} - [:div {:class (stl/css :modal-header)} - (if webhook - [:h2 {:class (stl/css :modal-title)} (tr "modals.edit-webhook.title")] - [:h2 {:class (stl/css :modal-title)} (tr "modals.create-webhook.title")]) + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:& fm/form {:form form :on-submit on-submit} + [:div {:class (stl/css :modal-header)} + (if webhook + [:h2 {:class (stl/css :modal-title)} (tr "modals.edit-webhook.title")] + [:h2 {:class (stl/css :modal-title)} (tr "modals.create-webhook.title")]) - [:button {:class (stl/css :modal-close-btn) - :on-click on-modal-close} i/close-refactor]] + [:button {:class (stl/css :modal-close-btn) + :on-click on-modal-close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "text" - :auto-focus? true - :form form - :name :uri - :label (tr "modals.create-webhook.url.label") - :placeholder (tr "modals.create-webhook.url.placeholder")}]] - [:div {:class (stl/css :fields-row)} - [:div {:class (stl/css :select-title)} (tr "dashboard.webhooks.content-type")] - [:& fm/select {:options valid-webhook-mtypes - :default "application/json" - :name :mtype}]] - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "checkbox" - :class (stl/css :custom-input-checkbox) - :form form - :name :is-active - :label (tr "dashboard.webhooks.active")}] - [:div {:class (stl/css :hint)} (tr "dashboard.webhooks.active.explain")]]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "text" + :auto-focus? true + :form form + :name :uri + :label (tr "modals.create-webhook.url.label") + :placeholder (tr "modals.create-webhook.url.placeholder")}]] + [:div {:class (stl/css :fields-row)} + [:div {:class (stl/css :select-title)} (tr "dashboard.webhooks.content-type")] + [:& fm/select {:options valid-webhook-mtypes + :default "application/json" + :name :mtype}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "checkbox" + :class (stl/css :custom-input-checkbox) + :form form + :name :is-active + :label (tr "dashboard.webhooks.active")}] + [:div {:class (stl/css :hint)} (tr "dashboard.webhooks.active.explain")]]] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.cancel") - :on-click #(modal/hide!)}] - [:> fm/submit-button* - {:label (if webhook - (tr "modals.edit-webhook.submit-label") - (tr "modals.create-webhook.submit-label"))}]]]]]] - - ;; OLD - [:div.modal-overlay - [:div.modal-container.webhooks-modal - [:& fm/form {:form form :on-submit on-submit} - - [:div.modal-header - [:div.modal-header-title - (if webhook - [:h2 (tr "modals.edit-webhook.title")] - [:h2 (tr "modals.create-webhook.title")])] - - [:div.modal-close-button - {:on-click #(st/emit! (modal/hide))} i/close]] - - [:div.modal-content.generic-form - [:div.fields-container - [:div.fields-row - [:& fm/input {:type "text" - :auto-focus? true - :form form - :name :uri - :label (tr "modals.create-webhook.url.label") - :placeholder (tr "modals.create-webhook.url.placeholder")}]] - - [:div.fields-row - [:& fm/select {:options valid-webhook-mtypes - :label (tr "dashboard.webhooks.content-type") - :default "application/json" - :name :mtype}]]] - [:div.fields-row - [:div.input-checkbox.check-primary - [:& fm/input {:type "checkbox" - :form form - :name :is-active - :label (tr "dashboard.webhooks.active")}]] - [:div.explain (tr "dashboard.webhooks.active.explain")]]] - - [:div.modal-footer - [:div.action-buttons - [:input.cancel-button - {:type "button" - :value (tr "labels.cancel") - :on-click #(modal/hide!)}] - [:> fm/submit-button* - {:label (if webhook - (tr "modals.edit-webhook.submit-label") - (tr "modals.create-webhook.submit-label"))}]]]]]]))) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:input {:class (stl/css :cancel-button) + :type "button" + :value (tr "labels.cancel") + :on-click #(modal/hide!)}] + [:> fm/submit-button* + {:label (if webhook + (tr "modals.edit-webhook.submit-label") + (tr "modals.create-webhook.submit-label"))}]]]]]])) (mf/defc webhooks-hero {::mf/wrap-props false} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :webhooks-hero-container)} - [:div {:class (stl/css :webhooks-hero)} - [:div {:class (stl/css :desc)} - [:h2 (tr "labels.webhooks")] - [:& i18n/tr-html {:label "dashboard.webhooks.description"}]] + [:div {:class (stl/css :webhooks-hero-container)} + [:div {:class (stl/css :webhooks-hero)} + [:div {:class (stl/css :desc)} + [:h2 (tr "labels.webhooks")] + [:& i18n/tr-html {:label "dashboard.webhooks.description"}]] - [:div - {:class (stl/css :btn-primary) - :on-click #(st/emit! (modal/show :webhook {}))} - [:span (tr "dashboard.webhooks.create")]]]] - - ;; OLD - [:div.webhooks-hero-container - [:div.webhooks-hero - [:div.desc - [:h2 (tr "labels.webhooks")] - [:& i18n/tr-html {:label "dashboard.webhooks.description"}]] - - [:div.btn-primary - {:on-click #(st/emit! (modal/show :webhook {}))} - [:span (tr "dashboard.webhooks.create")]]]]))) + [:div + {:class (stl/css :btn-primary) + :on-click #(st/emit! (modal/show :webhook {}))} + [:span (tr "dashboard.webhooks.create")]]]]) (mf/defc webhook-actions {::mf/wrap-props false} [{:keys [on-edit on-delete]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - show? (mf/use-state false) + (let [show? (mf/use-state false) on-show (mf/use-fn #(reset! show? true)) on-hide (mf/use-fn #(reset! show? false))] - - (if new-css-system - [:* - [:span {:class (stl/css :icon) - :on-click on-show} [i/actions]] - [:& dropdown {:show @show? :on-close on-hide} - [:ul {:class (stl/css :dropdown :actions-dropdown)} - [:li {:on-click on-edit} (tr "labels.edit")] - [:li {:on-click on-delete} (tr "labels.delete")]]]] - - ;; OLD - [:* - [:span.icon {:on-click on-show} [i/actions]] - [:& dropdown {:show @show? :on-close on-hide} - [:ul.dropdown.actions-dropdown - [:li {:on-click on-edit} (tr "labels.edit")] - [:li {:on-click on-delete} (tr "labels.delete")]]]]))) + + [:* + [:span {:class (stl/css :icon) + :on-click on-show} [i/actions]] + [:& dropdown {:show @show? :on-close on-hide} + [:ul {:class (stl/css :dropdown :actions-dropdown)} + [:li {:on-click on-edit} (tr "labels.edit")] + [:li {:on-click on-delete} (tr "labels.delete")]]]])) (mf/defc last-delivery-icon {::mf/wrap-props false} [{:keys [success? text]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :last-delivery-icon)} - [:div {:class (stl/css :tooltip)} - [:div {:class (stl/css :label)} text] - [:div {:class (stl/css :arrow-down)}]] - (if success? - [:span {:class (stl/css :icon :success)} i/msg-success] - [:span {:class (stl/css :icon :failure)} i/msg-warning])] - - ;; OLD - [:div.last-delivery-icon - [:div.tooltip - [:div.label text] - [:div.arrow-down]] - (if success? - [:span.icon.success i/msg-success] - [:span.icon.failure i/msg-warning])]))) + [:div {:class (stl/css :last-delivery-icon)} + [:div {:class (stl/css :tooltip)} + [:div {:class (stl/css :label)} text] + [:div {:class (stl/css :arrow-down)}]] + (if success? + [:span {:class (stl/css :icon :success)} i/msg-success] + [:span {:class (stl/css :icon :failure)} i/msg-warning])]) (mf/defc webhook-item {::mf/wrap [mf/memo]} [{:keys [webhook] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - error-code (:error-code webhook) + (let [error-code (:error-code webhook) id (:id webhook) on-edit @@ -1265,64 +908,36 @@ (str/starts-with? error-code "unexpected-status") (dm/str " " (tr "errors.webhooks.unexpected-status" (extract-status error-code))))))] - - (if new-css-system - [:div {:class (stl/css :table-row)} - [:div {:class (stl/css :table-field :last-delivery)} - [:div {:class (stl/css :icon-container)} - [:& last-delivery-icon - {:success? (nil? error-code) - :text last-delivery-text}]]] - [:div {:class (stl/css :table-field :uri)} - [:div (dm/str (:uri webhook))]] - [:div {:class (stl/css :table-field :active)} - [:div (if (:is-active webhook) - (tr "labels.active") - (tr "labels.inactive"))]] - [:div {:class (stl/css :table-field :actions)} - [:& webhook-actions - {:on-edit on-edit - :on-delete on-delete}]]] - ;; OLD - [:div.table-row - [:div.table-field.last-delivery - [:div.icon-container - [:& last-delivery-icon - {:success? (nil? error-code) - :text last-delivery-text}]]] - [:div.table-field.uri - [:div (dm/str (:uri webhook))]] - [:div.table-field.active - [:div (if (:is-active webhook) - (tr "labels.active") - (tr "labels.inactive"))]] - [:div.table-field.actions - [:& webhook-actions - {:on-edit on-edit - :on-delete on-delete}]]]))) + [:div {:class (stl/css :table-row)} + [:div {:class (stl/css :table-field :last-delivery)} + [:div {:class (stl/css :icon-container)} + [:& last-delivery-icon + {:success? (nil? error-code) + :text last-delivery-text}]]] + [:div {:class (stl/css :table-field :uri)} + [:div (dm/str (:uri webhook))]] + [:div {:class (stl/css :table-field :active)} + [:div (if (:is-active webhook) + (tr "labels.active") + (tr "labels.inactive"))]] + [:div {:class (stl/css :table-field :actions)} + [:& webhook-actions + {:on-edit on-edit + :on-delete on-delete}]]])) (mf/defc webhooks-list {::mf/wrap-props false} [{:keys [webhooks]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :dashboard-table)} - [:div {:class (stl/css :table-rows)} - (for [webhook webhooks] - [:& webhook-item {:webhook webhook :key (:id webhook)}])]] - - ;; OLD - [:div.dashboard-table - [:div.table-rows - (for [webhook webhooks] - [:& webhook-item {:webhook webhook :key (:id webhook)}])]]))) + [:div {:class (stl/css :dashboard-table)} + [:div {:class (stl/css :table-rows)} + (for [webhook webhooks] + [:& webhook-item {:webhook webhook :key (:id webhook)}])]]) (mf/defc team-webhooks-page {::mf/wrap-props false} [{:keys [team]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - webhooks (mf/deref refs/dashboard-team-webhooks)] + (let [webhooks (mf/deref refs/dashboard-team-webhooks)] (mf/with-effect [team] (dom/set-html-title @@ -1334,29 +949,16 @@ (mf/with-effect [team] (st/emit! (dd/fetch-team-webhooks))) - (if new-css-system + [:* + [:& header {:team team :section :dashboard-team-webhooks}] + [:section {:class (stl/css :dashboard-container :dashboard-team-webhooks)} [:* - [:& header {:team team :section :dashboard-team-webhooks}] - [:section {:class (stl/css :dashboard-container :dashboard-team-webhooks)} - [:* - [:& webhooks-hero] - (if (empty? webhooks) - [:div {:class (stl/css :webhooks-empty)} - [:div (tr "dashboard.webhooks.empty.no-webhooks")] - [:div (tr "dashboard.webhooks.empty.add-one")]] - [:& webhooks-list {:webhooks webhooks}])]]] - - ;; OLD - [:* - [:& header {:team team :section :dashboard-team-webhooks}] - [:section.dashboard-container.dashboard-team-webhooks - [:* - [:& webhooks-hero] - (if (empty? webhooks) - [:div.webhooks-empty - [:div (tr "dashboard.webhooks.empty.no-webhooks")] - [:div (tr "dashboard.webhooks.empty.add-one")]] - [:& webhooks-list {:webhooks webhooks}])]]]))) + [:& webhooks-hero] + (if (empty? webhooks) + [:div {:class (stl/css :webhooks-empty)} + [:div (tr "dashboard.webhooks.empty.no-webhooks")] + [:div (tr "dashboard.webhooks.empty.add-one")]] + [:& webhooks-list {:webhooks webhooks}])]]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SETTINGS SECTION @@ -1365,8 +967,7 @@ (mf/defc team-settings-page {::mf/wrap-props false} [{:keys [team]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - finput (mf/use-ref) + (let [finput (mf/use-ref) members-map (mf/deref refs/dashboard-team-members) owner (->> (vals members-map) @@ -1398,77 +999,40 @@ (st/emit! (dd/fetch-team-members team-id) (dd/fetch-team-stats team-id)))) - (if new-css-system - [:* - [:& header {:section :dashboard-team-settings :team team}] - [:section {:class (stl/css :dashboard-container :dashboard-team-settings)} - [:div {:class (stl/css :team-settings)} - [:div {:class (stl/css :horizontal-blocks)} - [:div {:class (stl/css :block :info-block)} - [:div {:class (stl/css :label)} (tr "dashboard.team-info")] - [:div {:class (stl/css :name)} (:name team)] - [:div {:class (stl/css :icon)} - (when can-edit? - [:span {:class (stl/css :update-overlay) - :on-click on-image-click} i/image]) - [:img {:src (cfg/resolve-team-photo-url team)}] - (when can-edit? - [:& file-uploader {:accept "image/jpeg,image/png" - :multi false - :ref finput - :on-selected on-file-selected}])]] + [:* + [:& header {:section :dashboard-team-settings :team team}] + [:section {:class (stl/css :dashboard-container :dashboard-team-settings)} + [:div {:class (stl/css :team-settings)} + [:div {:class (stl/css :horizontal-blocks)} + [:div {:class (stl/css :block :info-block)} + [:div {:class (stl/css :label)} (tr "dashboard.team-info")] + [:div {:class (stl/css :name)} (:name team)] + [:div {:class (stl/css :icon)} + (when can-edit? + [:span {:class (stl/css :update-overlay) + :on-click on-image-click} i/image]) + [:img {:src (cfg/resolve-team-photo-url team)}] + (when can-edit? + [:& file-uploader {:accept "image/jpeg,image/png" + :multi false + :ref finput + :on-selected on-file-selected}])]] - [:div {:class (stl/css :block :owner-block)} - [:div {:class (stl/css :label)} (tr "dashboard.team-members")] - [:div {:class (stl/css :owner)} - [:span {:class (stl/css :icon)} [:img {:src (cfg/resolve-profile-photo-url owner)}]] - [:span {:class (stl/css :text)} (str (:name owner) " (" (tr "labels.owner") ")")]] - [:div {:class (stl/css :summary)} - [:span {:class (stl/css :icon)} i/user] - [:span {:class (stl/css :text)} (tr "dashboard.num-of-members" (count members-map))]]] + [:div {:class (stl/css :block :owner-block)} + [:div {:class (stl/css :label)} (tr "dashboard.team-members")] + [:div {:class (stl/css :owner)} + [:span {:class (stl/css :icon)} [:img {:src (cfg/resolve-profile-photo-url owner)}]] + [:span {:class (stl/css :text)} (str (:name owner) " (" (tr "labels.owner") ")")]] + [:div {:class (stl/css :summary)} + [:span {:class (stl/css :icon)} i/user] + [:span {:class (stl/css :text)} (tr "dashboard.num-of-members" (count members-map))]]] - [:div {:class (stl/css :block :stats-block)} - [:div {:class (stl/css :label)} (tr "dashboard.team-projects")] - [:div {:class (stl/css :projects)} - [:span {:class (stl/css :icon)} i/folder] - [:span {:class (stl/css :text)} (tr "labels.num-of-projects" (i18n/c (dec (:projects stats))))]] - [:div {:class (stl/css :files)} - [:span {:class (stl/css :icon)} i/file-html] - [:span {:class (stl/css :text)} (tr "labels.num-of-files" (i18n/c (:files stats)))]]]]]]] - - [:* - [:& header {:section :dashboard-team-settings :team team}] - [:section.dashboard-container.dashboard-team-settings - [:div.team-settings - [:div.horizontal-blocks - [:div.block.info-block - [:div.label (tr "dashboard.team-info")] - [:div.name (:name team)] - [:div.icon - (when can-edit? - [:span.update-overlay {:on-click on-image-click} i/image]) - [:img {:src (cfg/resolve-team-photo-url team)}] - (when can-edit? - [:& file-uploader {:accept "image/jpeg,image/png" - :multi false - :ref finput - :on-selected on-file-selected}])]] - - [:div.block.owner-block - [:div.label (tr "dashboard.team-members")] - [:div.owner - [:span.icon [:img {:src (cfg/resolve-profile-photo-url owner)}]] - [:span.text (str (:name owner) " (" (tr "labels.owner") ")")]] - [:div.summary - [:span.icon i/user] - [:span.text (tr "dashboard.num-of-members" (count members-map))]]] - - [:div.block.stats-block - [:div.label (tr "dashboard.team-projects")] - [:div.projects - [:span.icon i/folder] - [:span.text (tr "labels.num-of-projects" (i18n/c (dec (:projects stats))))]] - [:div.files - [:span.icon i/file-html] - [:span.text (tr "labels.num-of-files" (i18n/c (:files stats)))]]]]]]]))) + [:div {:class (stl/css :block :stats-block)} + [:div {:class (stl/css :label)} (tr "dashboard.team-projects")] + [:div {:class (stl/css :projects)} + [:span {:class (stl/css :icon)} i/folder] + [:span {:class (stl/css :text)} (tr "labels.num-of-projects" (i18n/c (dec (:projects stats))))]] + [:div {:class (stl/css :files)} + [:span {:class (stl/css :icon)} i/file-html] + [:span {:class (stl/css :text)} (tr "labels.num-of-files" (i18n/c (:files stats)))]]]]]]])) diff --git a/frontend/src/app/main/ui/dashboard/team_form.cljs b/frontend/src/app/main/ui/dashboard/team_form.cljs index 08a8d1df89..258459beea 100644 --- a/frontend/src/app/main/ui/dashboard/team_form.cljs +++ b/frontend/src/app/main/ui/dashboard/team_form.cljs @@ -13,7 +13,6 @@ [app.main.data.modal :as modal] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] @@ -70,73 +69,42 @@ (mf/defc team-form-modal {::mf/register modal/components ::mf/register-as :team-form} [{:keys [team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - initial (mf/use-memo (fn [] (or team {}))) + (let [initial (mf/use-memo (fn [] (or team {}))) form (fm/use-form :spec ::team-form :validators [(fm/validate-not-empty :name (tr "auth.name.not-all-space")) (fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))] :initial initial) on-close #(st/emit! (modal/hide))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:& fm/form {:form form :on-submit on-submit} + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:& fm/form {:form form :on-submit on-submit} - [:div {:class (stl/css :modal-header)} - (if team - [:h2 {:class (stl/css :modal-title)} - (tr "labels.rename-team")] - [:h2 {:class (stl/css :modal-title)} - (tr "labels.create-team")]) + [:div {:class (stl/css :modal-header)} + (if team + [:h2 {:class (stl/css :modal-title)} + (tr "labels.rename-team")] + [:h2 {:class (stl/css :modal-title)} + (tr "labels.create-team")]) - [:button {:class (stl/css :modal-close-btn) - :on-click on-close} i/close-refactor]] + [:button {:class (stl/css :modal-close-btn) + :on-click on-close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:& fm/input {:type "text" - :auto-focus? true - :class (stl/css :group-name-input) - :form form - :name :name - :placeholder "E.g. Design" - :label (tr "labels.create-team.placeholder")}]] + [:div {:class (stl/css :modal-content)} + [:& fm/input {:type "text" + :auto-focus? true + :class (stl/css :group-name-input) + :form form + :name :name + :placeholder "E.g. Design" + :label (tr "labels.create-team.placeholder")}]] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:> fm/submit-button* - {:label (if team - (tr "labels.update-team") - (tr "labels.create-team")) - :className (stl/css :accept-btn)}]]]]]] - - - - [:div.modal-overlay - [:div.modal-container.team-form-modal - [:& fm/form {:form form :on-submit on-submit} - - [:div.modal-header - [:div.modal-header-title - (if team - [:h2 (tr "labels.rename-team")] - [:h2 (tr "labels.create-team")])] - - [:div.modal-close-button - {:on-click #(st/emit! (modal/hide))} i/close]] - - [:div.modal-content.generic-form - [:& fm/input {:type "text" - :auto-focus? true - :form form - :name :name - :label (tr "labels.create-team.placeholder")}]] - - [:div.modal-footer - [:div.action-buttons - [:> fm/submit-button* - {:label (if team - (tr "labels.update-team") - (tr "labels.create-team"))}]]]]]]))) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:> fm/submit-button* + {:label (if team + (tr "labels.update-team") + (tr "labels.create-team")) + :className (stl/css :accept-btn)}]]]]]])) diff --git a/frontend/src/app/main/ui/delete_shared.cljs b/frontend/src/app/main/ui/delete_shared.cljs index a1e341f45a..f51f62df1e 100644 --- a/frontend/src/app/main/ui/delete_shared.cljs +++ b/frontend/src/app/main/ui/delete_shared.cljs @@ -11,7 +11,6 @@ [app.main.data.modal :as modal] [app.main.repo :as rp] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -27,8 +26,7 @@ ::mf/register-as :delete-shared-libraries ::mf/wrap-props false} [{:keys [ids on-accept on-cancel accept-style origin count-libraries]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - references* (mf/use-state {}) + (let [references* (mf/use-state {}) references (deref references*) on-accept (or on-accept noop) @@ -96,91 +94,43 @@ (let [key (events/listen js/document "keydown" on-keydown)] (partial events/unlistenByKey key)))) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} title] - [:button {:class (stl/css :modal-close-btn) - :on-click cancel-fn} i/close-refactor]] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} title] + [:button {:class (stl/css :modal-close-btn) + :on-click cancel-fn} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - (when (and (string? subtitle) (not= subtitle "")) - [:h3 {:class (stl/css :modal-subtitle)} subtitle]) - (when (not= 0 count-libraries) - (if (pos? (count references)) - [:* - [:div - (when (and (string? scd-msg) (not= scd-msg "")) - [:h3 {:class (stl/css :modal-scd-msg)} scd-msg]) - [:ul {:class (stl/css :element-list)} - (for [[file-id file-name] references] - [:li {:class (stl/css :list-item) - :key (dm/str file-id)} - [:span "- " file-name]])]] - (when (and (string? hint) (not= hint "")) - [:h3 {:class (stl/css :modal-hint)}hint])] - [:* - [:h3 {:class (stl/css :modal-msg)} no-files-msg]]))] + [:div {:class (stl/css :modal-content)} + (when (and (string? subtitle) (not= subtitle "")) + [:h3 {:class (stl/css :modal-subtitle)} subtitle]) + (when (not= 0 count-libraries) + (if (pos? (count references)) + [:* + [:div + (when (and (string? scd-msg) (not= scd-msg "")) + [:h3 {:class (stl/css :modal-scd-msg)} scd-msg]) + [:ul {:class (stl/css :element-list)} + (for [[file-id file-name] references] + [:li {:class (stl/css :list-item) + :key (dm/str file-id)} + [:span "- " file-name]])]] + (when (and (string? hint) (not= hint "")) + [:h3 {:class (stl/css :modal-hint)} hint])] + [:* + [:h3 {:class (stl/css :modal-msg)} no-files-msg]]))] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - (when-not (= cancel-label :omit) - [:input {:class (stl/css :cancel-button) - :type "button" - :value cancel-label - :on-click cancel-fn}]) - - [:input {:class (stl/css-case :accept-btn true - :danger (= accept-style :danger) - :primary (= accept-style :primary)) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + (when-not (= cancel-label :omit) + [:input {:class (stl/css :cancel-button) :type "button" - :value accept-label - :on-click accept-fn}]]]]] + :value cancel-label + :on-click cancel-fn}]) - - [:div.modal-overlay - [:div.modal-container.confirm-dialog - [:div.modal-header - [:div.modal-header-title - [:h2 title]] - [:div.modal-close-button - {:on-click cancel-fn} i/close]] - - [:div.modal-content.delete-shared - (when (and (string? subtitle) (not= subtitle "")) - [:h3 subtitle]) - (when (not= 0 count-libraries) - (if (pos? (count references)) - [:* - [:div - (when (and (string? scd-msg) (not= scd-msg "")) - [:h3 scd-msg]) - [:ul.file-list - (for [[file-id file-name] references] - [:li.modal-item-element - {:key (dm/str file-id)} - [:span "- " file-name]])]] - (when (and (string? hint) (not= hint "")) - [:h3 hint])] - [:* - [:h3 no-files-msg]]))] - - [:div.modal-footer - [:div.action-buttons - (when-not (= cancel-label :omit) - [:input.cancel-button - {:type "button" - :value cancel-label - :on-click cancel-fn}]) - - [:input.accept-button - {:class (dom/classnames - :danger (= accept-style :danger) - :primary (= accept-style :primary)) - :type "button" - :value accept-label - :on-click accept-fn}]]]]] - ) - - )) + [:input {:class (stl/css-case :accept-btn true + :danger (= accept-style :danger) + :primary (= accept-style :primary)) + :type "button" + :value accept-label + :on-click accept-fn}]]]]])) diff --git a/frontend/src/app/main/ui/delete_shared.scss b/frontend/src/app/main/ui/delete_shared.scss index caa20bdcbb..84ec2e9b54 100644 --- a/frontend/src/app/main/ui/delete_shared.scss +++ b/frontend/src/app/main/ui/delete_shared.scss @@ -11,45 +11,53 @@ &.transparent { background-color: transparent; } - .modal-container { - @extend .modal-container-base; - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } - .modal-content { - @include titleTipography; - margin-bottom: $s-24; - .modal-hint { - @extend .modal-hint-base; - } - .element-list { - @include titleTipography; - .list-item { - @include titleTipography; - } - } - } - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-btn { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } - } +} + +.modal-container { + @extend .modal-container-base; +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + margin-bottom: $s-24; +} + +.modal-hint { + @extend .modal-hint-base; +} + +.element-list { + @include titleTipography; + .list-item { + @include titleTipography; + } +} + +.action-buttons { + @extend .modal-action-btns; +} + +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; } } diff --git a/frontend/src/app/main/ui/messages.cljs b/frontend/src/app/main/ui/messages.cljs index f04919fc67..489eae2a60 100644 --- a/frontend/src/app/main/ui/messages.cljs +++ b/frontend/src/app/main/ui/messages.cljs @@ -14,96 +14,52 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.link-button :as lb] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.util.dom :as dom] [rumext.v2 :as mf])) (mf/defc banner [{:keys [type position status controls content links actions on-close data-test role] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css-case :banner true - :warning (= type :warning) - :error (= type :error) - :success (= type :success) - :info (= type :info) - :fixed (= position :fixed) - :floating (= position :floating) - :inline (= position :inline) - :hide (= status :hide))} - [:div {:class (stl/css :wrapper)} - [:div {:class (stl/css :icon)} - (case type - :warning i/msg-warning-refactor - :error i/msg-error-refactor - :success i/msg-success-refactor - :info i/msg-neutral-refactor - i/msg-error-refactor)] + [:div {:class (stl/css-case :banner true + :warning (= type :warning) + :error (= type :error) + :success (= type :success) + :info (= type :info) + :fixed (= position :fixed) + :floating (= position :floating) + :inline (= position :inline) + :hide (= status :hide))} + [:div {:class (stl/css :wrapper)} + [:div {:class (stl/css :icon)} + (case type + :warning i/msg-warning-refactor + :error i/msg-error-refactor + :success i/msg-success-refactor + :info i/msg-neutral-refactor + i/msg-error-refactor)] - [:div {:class (stl/css-case :content true - :inline-actions (= controls :inline-actions) - :bottom-actions (= controls :bottom-actions)) - :data-test data-test - :role role} - [:span {:class (stl/css :text)} - content - (for [[index link] (d/enumerate links)] - [:* {:key (dm/str "link-" index)} - " " [:& lb/link-button {:class "link" - :on-click (:callback link) - :value (:label link)}]])] + [:div {:class (stl/css-case :content true + :inline-actions (= controls :inline-actions) + :bottom-actions (= controls :bottom-actions)) + :data-test data-test + :role role} + [:span {:class (stl/css :text)} + content + (for [[index link] (d/enumerate links)] + [:* {:key (dm/str "link-" index)} + " " [:& lb/link-button {:class "link" + :on-click (:callback link) + :value (:label link)}]])] - (when (or (= controls :bottom-actions) (= controls :inline-actions)) - [:div {:class (stl/css :actions)} - (for [action actions] - [:button {:key (uuid/next) - :class (stl/css :action-bnt) - :on-click (:callback action)} - (:label action)])])] - (when (= controls :close) - [:button {:class (stl/css :btn-close) - :on-click on-close} i/close-refactor])]] - - - - [:div.banner {:class (dom/classnames - :warning (= type :warning) - :error (= type :error) - :success (= type :success) - :info (= type :info) - :fixed (= position :fixed) - :floating (= position :floating) - :inline (= position :inline) - :hide (= status :hide))} - [:div.wrapper - [:div.icon (case type - :warning i/msg-warning - :error i/msg-error - :success i/msg-success - :info i/msg-info - i/msg-error)] - [:div.content {:class (dom/classnames - :inline-actions (= controls :inline-actions) - :bottom-actions (= controls :bottom-actions)) - :data-test data-test - :role role} - [:span - content - (for [[index link] (d/enumerate links)] - [:* {:key (dm/str "link-" index)} - " " [:& lb/link-button {:class "link" - :on-click (:callback link) - :value (:label link)}]])] - - (when (or (= controls :bottom-actions) (= controls :inline-actions)) - [:div.actions - (for [action actions] - [:div.btn-secondary.btn-small {:key (uuid/next) - :on-click (:callback action)} - (:label action)])])] - (when (= controls :close) - [:div.btn-close {:on-click on-close} i/close])]]))) + (when (or (= controls :bottom-actions) (= controls :inline-actions)) + [:div {:class (stl/css :actions)} + (for [action actions] + [:button {:key (uuid/next) + :class (stl/css :action-bnt) + :on-click (:callback action)} + (:label action)])])] + (when (= controls :close) + [:button {:class (stl/css :btn-close) + :on-click on-close} i/close-refactor])]]) (mf/defc notifications [] diff --git a/frontend/src/app/main/ui/messages.scss b/frontend/src/app/main/ui/messages.scss index 1479f2f142..e2a571c8f7 100644 --- a/frontend/src/app/main/ui/messages.scss +++ b/frontend/src/app/main/ui/messages.scss @@ -100,15 +100,6 @@ @include titleTipography; } -.inline-actions { -} - -.bottom-actions { -} - -.actions { -} - .action-btn { @extend .button-tertiary; height: $s-32; diff --git a/frontend/src/app/main/ui/modal.cljs b/frontend/src/app/main/ui/modal.cljs index 3ed224d1a3..a7eb37a45a 100644 --- a/frontend/src/app/main/ui/modal.cljs +++ b/frontend/src/app/main/ui/modal.cljs @@ -51,7 +51,6 @@ (let [data (unchecked-get props "data") wrapper-ref (mf/use-ref nil) components (mf/deref dm/components) - new-css-system (mf/use-ctx ctx/new-css-system) allow-click-outside (:allow-click-outside data) @@ -78,9 +77,7 @@ (when-let [component (get components (:type data))] [:div {:ref wrapper-ref - :class (stl/css-case - :modal-wrapper new-css-system - :global/modal-wrapper (not new-css-system))} + :class (stl/css :modal-wrapper)} (mf/element component (:props data))]))) (def modal-ref diff --git a/frontend/src/app/main/ui/onboarding.cljs b/frontend/src/app/main/ui/onboarding.cljs index 8b9801d8a1..b16589df32 100644 --- a/frontend/src/app/main/ui/onboarding.cljs +++ b/frontend/src/app/main/ui/onboarding.cljs @@ -13,7 +13,6 @@ [app.main.data.modal :as modal] [app.main.data.users :as du] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.onboarding.newsletter] [app.main.ui.onboarding.questions] [app.main.ui.onboarding.team-choice] @@ -33,178 +32,113 @@ (mf/defc onboarding-welcome [{:keys [next] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - go-next + (let [go-next (fn [] (send-event "onboarding-step1-continue") (next))] - (if new-css-system - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-left)} - [:img {:src "images/onboarding-welcome.png" - :border "0" - :alt (tr "onboarding.welcome.alt")}]] - [:div {:class (stl/css :modal-right)} - [:div {:class (stl/css :release)} - "Version " (:main cf/version)] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title) - :data-test "onboarding-welcome"} - (tr "onboarding-v2.welcome.title")]] + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-left)} + [:img {:src "images/onboarding-welcome.png" + :border "0" + :alt (tr "onboarding.welcome.alt")}]] + [:div {:class (stl/css :modal-right)} + [:div {:class (stl/css :release)} + "Version " (:main cf/version)] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title) + :data-test "onboarding-welcome"} + (tr "onboarding-v2.welcome.title")]] - [:div {:class (stl/css :modal-info)} - [:p {:class (stl/css :modal-text)} - (tr "onboarding-v2.welcome.desc1")] - [:div {:class (stl/css :property-block)} - [:img {:src "images/community.svg" - :border "0"}] - [:div {:class (stl/css :text-wrapper)} - [:div {:class (stl/css :property-title)} - [:a {:href "https://community.penpot.app/" - :target "_blank" - :on-click #(send-event "onboarding-community-link")} - (tr "onboarding-v2.welcome.desc2.title")]] - [:div {:class (stl/css :property-description)} - (tr "onboarding-v2.welcome.desc2")]]] + [:div {:class (stl/css :modal-info)} + [:p {:class (stl/css :modal-text)} + (tr "onboarding-v2.welcome.desc1")] + [:div {:class (stl/css :property-block)} + [:img {:src "images/community.svg" + :border "0"}] + [:div {:class (stl/css :text-wrapper)} + [:div {:class (stl/css :property-title)} + [:a {:href "https://community.penpot.app/" + :target "_blank" + :on-click #(send-event "onboarding-community-link")} + (tr "onboarding-v2.welcome.desc2.title")]] + [:div {:class (stl/css :property-description)} + (tr "onboarding-v2.welcome.desc2")]]] - [:div {:class (stl/css :property-block)} - [:img {:src "images/contributing.svg" - :border "0"}] - [:div {:class (stl/css :text-wrapper)} - [:div {:class (stl/css :property-title)} - [:a {:href "https://help.penpot.app/contributing-guide/" - :target "_blank" :on-click #(send-event "onboarding-contributing-link")} - (tr "onboarding-v2.welcome.desc3.title")]] - [:div {:class (stl/css :property-description)} - (tr "onboarding-v2.welcome.desc3")]]]]] + [:div {:class (stl/css :property-block)} + [:img {:src "images/contributing.svg" + :border "0"}] + [:div {:class (stl/css :text-wrapper)} + [:div {:class (stl/css :property-title)} + [:a {:href "https://help.penpot.app/contributing-guide/" + :target "_blank" :on-click #(send-event "onboarding-contributing-link")} + (tr "onboarding-v2.welcome.desc3.title")]] + [:div {:class (stl/css :property-description)} + (tr "onboarding-v2.welcome.desc3")]]]]] - [:div {:class (stl/css :modal-footer)} - [:button {:on-click go-next - :data-test "onboarding-next-btn"} - (tr "labels.continue")]]]] - - - [:div.modal-container.onboarding.onboarding-v2 - [:div.modal-left.welcome - [:img {:src "images/onboarding-welcome.png" :border "0" :alt (tr "onboarding.welcome.alt")}]] - [:div.modal-right - [:div.release-container [:span.release "Version " (:main cf/version)]] - [:div.right-content - [:div.modal-title - [:h2 {:data-test "onboarding-welcome"} (tr "onboarding-v2.welcome.title")]] - - [:div.modal-content - [:p (tr "onboarding-v2.welcome.desc1")] - [:div.welcome-card - [:img {:src "images/community.svg" :border "0"}] - [:div - [:div.title [:a {:href "https://community.penpot.app/" :target "_blank" :on-click #(send-event "onboarding-community-link")} (tr "onboarding-v2.welcome.desc2.title")]] - [:div.description (tr "onboarding-v2.welcome.desc2")]]] - - [:div.welcome-card - [:img {:src "images/contributing.svg" :border "0"}] - [:div - [:div.title [:a {:href "https://help.penpot.app/contributing-guide/" :target "_blank" :on-click #(send-event "onboarding-contributing-link")} (tr "onboarding-v2.welcome.desc3.title")]] - [:div.description (tr "onboarding-v2.welcome.desc3")]]]]] - [:div.modal-navigation - [:button.btn-secondary {:on-click go-next :data-test "onboarding-next-btn"} (tr "labels.continue")]] - [:img.deco.square {:src "images/deco-square.svg" :border "0"}] - [:img.deco.circle {:src "images/deco-circle.svg" :border "0"}] - [:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}] - [:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]))) + [:div {:class (stl/css :modal-footer)} + [:button {:on-click go-next + :data-test "onboarding-next-btn"} + (tr "labels.continue")]]]])) (mf/defc onboarding-before-start [{:keys [next] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - go-next + (let [go-next (fn [] (send-event "onboarding-step2-continue") (next))] - (if new-css-system - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-left)} - [:img {:src "images/onboarding-people.png" - :border "0" - :alt (tr "onboarding.welcome.alt")}]] - [:div {:class (stl/css :modal-right)} - [:div {:class (stl/css :release)} - "Version " (:main cf/version)] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title) - :data-test "onboarding-welcome"} - (tr "onboarding-v2.before-start.title")]] + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-left)} + [:img {:src "images/onboarding-people.png" + :border "0" + :alt (tr "onboarding.welcome.alt")}]] + [:div {:class (stl/css :modal-right)} + [:div {:class (stl/css :release)} + "Version " (:main cf/version)] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title) + :data-test "onboarding-welcome"} + (tr "onboarding-v2.before-start.title")]] - [:div {:class (stl/css :modal-info)} - [:p {:class (stl/css :modal-text)} - (tr "onboarding-v2.before-start.desc1")] - [:div {:class (stl/css :property-block)} - [:img {:src "images/user-guide.svg" :border "0"}] - [:div {:class (stl/css :text-wrapper)} - [:div {:class (stl/css :property-title)} - [:a {:class (stl/css :modal-link) - :href "https://help.penpot.app/user-guide/" - :target "_blank" - :on-click #(send-event "onboarding-user-guide-link")} - (tr "onboarding-v2.before-start.desc2.title")]] - [:div {:class (stl/css :property-description)} - (tr "onboarding-v2.before-start.desc2")]]] + [:div {:class (stl/css :modal-info)} + [:p {:class (stl/css :modal-text)} + (tr "onboarding-v2.before-start.desc1")] + [:div {:class (stl/css :property-block)} + [:img {:src "images/user-guide.svg" :border "0"}] + [:div {:class (stl/css :text-wrapper)} + [:div {:class (stl/css :property-title)} + [:a {:class (stl/css :modal-link) + :href "https://help.penpot.app/user-guide/" + :target "_blank" + :on-click #(send-event "onboarding-user-guide-link")} + (tr "onboarding-v2.before-start.desc2.title")]] + [:div {:class (stl/css :property-description)} + (tr "onboarding-v2.before-start.desc2")]]] - [:div {:class (stl/css :property-block)} - [:img {:src "images/video-tutorials.svg" :border "0"}] - [:div {:class (stl/css :text-wrapper)} - [:div {:class (stl/css :property-title)} - [:a {:class (stl/css :modal-link) - :href "https://www.youtube.com/c/Penpot" - :target "_blank" - :on-click #(send-event "onboarding-video-tutorials-link")} - (tr "onboarding-v2.before-start.desc3.title")]] - [:div {:class (stl/css :property-description)} - (tr "onboarding-v2.before-start.desc3")]]]]] + [:div {:class (stl/css :property-block)} + [:img {:src "images/video-tutorials.svg" :border "0"}] + [:div {:class (stl/css :text-wrapper)} + [:div {:class (stl/css :property-title)} + [:a {:class (stl/css :modal-link) + :href "https://www.youtube.com/c/Penpot" + :target "_blank" + :on-click #(send-event "onboarding-video-tutorials-link")} + (tr "onboarding-v2.before-start.desc3.title")]] + [:div {:class (stl/css :property-description)} + (tr "onboarding-v2.before-start.desc3")]]]]] - [:div {:class (stl/css :modal-footer)} - [:button {:on-click go-next - :data-test "onboarding-next-btn"} - (tr "labels.continue")]]]] - - - [:div.modal-container.onboarding.onboarding-v2 - [:div.modal-left.welcome - [:img {:src "images/onboarding-people.png" :border "0" :alt (tr "onboarding.welcome.alt")}]] - [:div.modal-right - [:div.release-container [:span.release "Version " (:main cf/version)]] - [:div.right-content - [:div.modal-title - [:h2 {:data-test "onboarding-welcome"} (tr "onboarding-v2.before-start.title")]] - - [:div.modal-content - [:p (tr "onboarding-v2.before-start.desc1")] - [:div.welcome-card - [:img {:src "images/user-guide.svg" :border "0"}] - [:div - [:div.title [:a {:href "https://help.penpot.app/user-guide/" :target "_blank" :on-click #(send-event "onboarding-user-guide-link")} (tr "onboarding-v2.before-start.desc2.title")]] - [:div.description (tr "onboarding-v2.before-start.desc2")]]] - - [:div.welcome-card - [:img {:src "images/video-tutorials.svg" :border "0"}] - [:div - [:div.title [:a {:href "https://www.youtube.com/c/Penpot" :target "_blank" :on-click #(send-event "onboarding-video-tutorials-link")} (tr "onboarding-v2.before-start.desc3.title")]] - [:div.description (tr "onboarding-v2.before-start.desc3")]]]]] - [:div.modal-navigation - [:button.btn-secondary {:on-click go-next :data-test "onboarding-next-btn"} (tr "labels.continue")]] - [:img.deco.square {:src "images/deco-square.svg" :border "0"}] - [:img.deco.circle {:src "images/deco-circle.svg" :border "0"}] - [:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}] - [:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]))) + [:div {:class (stl/css :modal-footer)} + [:button {:on-click go-next + :data-test "onboarding-next-btn"} + (tr "labels.continue")]]]])) (mf/defc onboarding-modal {::mf/register modal/components ::mf/register-as :onboarding} [_] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - slide (mf/use-state :start) + (let [slide (mf/use-state :start) klass (mf/use-state "fadeInDown") navigate @@ -230,15 +164,8 @@ (reset! klass nil) (tm/dispose! sem)))) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div.animated {:class(dm/str @klass " " (stl/css :animated))} - (case @slide - :start [:& onboarding-welcome {:next #(navigate :opensource)}] - :opensource [:& onboarding-before-start {:next skip}])]] - - [:div.modal-overlay - [:div.animated {:class @klass} - (case @slide - :start [:& onboarding-welcome {:next #(navigate :opensource)}] - :opensource [:& onboarding-before-start {:next skip}])]]))) + [:div {:class (stl/css :modal-overlay)} + [:div.animated {:class (dm/str @klass " " (stl/css :animated))} + (case @slide + :start [:& onboarding-welcome {:next #(navigate :opensource)}] + :opensource [:& onboarding-before-start {:next skip}])]])) diff --git a/frontend/src/app/main/ui/onboarding/newsletter.cljs b/frontend/src/app/main/ui/onboarding/newsletter.cljs index c147a7d5ec..e252452857 100644 --- a/frontend/src/app/main/ui/onboarding/newsletter.cljs +++ b/frontend/src/app/main/ui/onboarding/newsletter.cljs @@ -11,7 +11,6 @@ [app.main.data.modal :as modal] [app.main.data.users :as du] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -20,8 +19,7 @@ {::mf/register modal/components ::mf/register-as :onboarding-newsletter-modal} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - message (tr "onboarding.newsletter.acceptance-message") + (let [message (tr "onboarding.newsletter.acceptance-message") newsletter-updates (mf/use-state false) newsletter-news (mf/use-state false) toggle @@ -39,78 +37,49 @@ (modal/show {:type :onboarding-team}) (du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news}))))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div.animated.fadeInDown {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title) - :data-test "onboarding-newsletter-title"} - (tr "onboarding.newsletter.title")] - [:p {:class (stl/css :modal-text)} - (tr "onboarding-v2.newsletter.desc")]] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :newsletter-options)} - [:div {:class (stl/css :input-wrapper)} - [:label {:for "newsletter-updates"} - [:span {:class (stl/css-case :global/checked @newsletter-updates)} - (when @newsletter-updates - i/status-tick-refactor)] - (tr "onboarding-v2.newsletter.updates") - [:input {:type "checkbox" - :id "newsletter-updates" - :on-change #(toggle newsletter-updates)}]]] + [:div {:class (stl/css :modal-overlay)} + [:div.animated.fadeInDown {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title) + :data-test "onboarding-newsletter-title"} + (tr "onboarding.newsletter.title")] + [:p {:class (stl/css :modal-text)} + (tr "onboarding-v2.newsletter.desc")]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :newsletter-options)} + [:div {:class (stl/css :input-wrapper)} + [:label {:for "newsletter-updates"} + [:span {:class (stl/css-case :global/checked @newsletter-updates)} + (when @newsletter-updates + i/status-tick-refactor)] + (tr "onboarding-v2.newsletter.updates") + [:input {:type "checkbox" + :id "newsletter-updates" + :on-change #(toggle newsletter-updates)}]]] - [:div {:class (stl/css :input-wrapper)} - [:label {:for "newsletter-news"} - [:span {:class (stl/css-case :global/checked @newsletter-news)} - (when @newsletter-news - i/status-tick-refactor)] - (tr "onboarding-v2.newsletter.news") - [:input {:type "checkbox" - :id "newsletter-news" - :on-change #(toggle newsletter-news)}]]]] + [:div {:class (stl/css :input-wrapper)} + [:label {:for "newsletter-news"} + [:span {:class (stl/css-case :global/checked @newsletter-news)} + (when @newsletter-news + i/status-tick-refactor)] + (tr "onboarding-v2.newsletter.news") + [:input {:type "checkbox" + :id "newsletter-news" + :on-change #(toggle newsletter-news)}]]]] - [:div {:class (stl/css :modal-info)} - [:p {:class (stl/css :modal-text)} - (tr "onboarding-v2.newsletter.privacy1") - [:a {:class (stl/css :modal-link) - :target "_blank" - :href "https://penpot.app/privacy"} - (tr "onboarding.newsletter.policy")]] - [:p {:class (stl/css :modal-text)} - (tr "onboarding-v2.newsletter.privacy2")]]] + [:div {:class (stl/css :modal-info)} + [:p {:class (stl/css :modal-text)} + (tr "onboarding-v2.newsletter.privacy1") + [:a {:class (stl/css :modal-link) + :target "_blank" + :href "https://penpot.app/privacy"} + (tr "onboarding.newsletter.policy")]] + [:p {:class (stl/css :modal-text)} + (tr "onboarding-v2.newsletter.privacy2")]]] - [:div {:class (stl/css :modal-footer)} - [:button {:on-click accept} (tr "labels.continue")]] + [:div {:class (stl/css :modal-footer)} + [:button {:on-click accept} (tr "labels.continue")]] - [:img {:class (stl/css-case :deco true - :top true) - :src "images/deco-newsletter.png" :border "0"}]]] - - - - [:div.modal-overlay - [:div.modal-container.onboarding.newsletter.animated.fadeInDown - [:div.modal-top - [:h1.newsletter-title {:data-test "onboarding-newsletter-title"} (tr "onboarding.newsletter.title")] - [:p (tr "onboarding-v2.newsletter.desc")]] - [:div.modal-bottom - [:div.newsletter-options - [:div.input-checkbox.check-primary - [:input {:type "checkbox" - :id "newsletter-updates" - :on-change #(toggle newsletter-updates)}] - [:label {:for "newsletter-updates"} (tr "onboarding-v2.newsletter.updates")]] - [:div.input-checkbox.check-primary - [:input {:type "checkbox" - :id "newsletter-news" - :on-change #(toggle newsletter-news)}] - [:label {:for "newsletter-news"} (tr "onboarding-v2.newsletter.news")]]] - [:p (tr "onboarding-v2.newsletter.privacy1") [:a {:target "_blank" :href "https://penpot.app/privacy"} (tr "onboarding.newsletter.policy")]] - [:p (tr "onboarding-v2.newsletter.privacy2")]] - [:div.modal-footer - [:button.btn-primary {:on-click accept} (tr "labels.continue")]] - [:img.deco.top {:src "images/deco-newsletter.png" :border "0"}] - [:img.deco.newsletter-left {:src "images/deco-news-left.png" :border "0"}] - [:img.deco.newsletter-right {:src "images/deco-news-right.png" :border "0"}]]]) - )) + [:img {:class (stl/css-case :deco true + :top true) + :src "images/deco-newsletter.png" :border "0"}]]])) diff --git a/frontend/src/app/main/ui/onboarding/team_choice.cljs b/frontend/src/app/main/ui/onboarding/team_choice.cljs index bb2d5c977c..f850128ac6 100644 --- a/frontend/src/app/main/ui/onboarding/team_choice.cljs +++ b/frontend/src/app/main/ui/onboarding/team_choice.cljs @@ -15,7 +15,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] @@ -30,64 +29,38 @@ (mf/defc team-modal-right [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - - [:div {:class (stl/css :modal-right)} - [:h2 {:class (stl/css :modal-subtitle)} - (tr "onboarding.team-modal.create-team")] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.team-modal.create-team-desc")] - [:ul {:class (stl/css :team-features)} - [:li {:class (stl/css :feature)} - [:span {:class (stl/css :icon)} i/document-refactor] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.team-modal.create-team-feature-1")]] - [:li {:class (stl/css :feature)} - [:span {:class (stl/css :icon)} i/move-refactor] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.team-modal.create-team-feature-2")]] - [:li {:class (stl/css :feature)} - [:span {:class (stl/css :icon)} i/tree-refactor] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.team-modal.create-team-feature-3")]] - [:li {:class (stl/css :feature)} - [:span {:class (stl/css :icon)} i/user-refactor] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.team-modal.create-team-feature-4")]] - [:li {:class (stl/css :feature)} - [:span {:class (stl/css :icon)} i/tick-refactor] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.team-modal.create-team-feature-5")]]]] - - - - [:div.team-right - [:h2.subtitle (tr "onboarding.team-modal.create-team")] - [:p.info (tr "onboarding.team-modal.create-team-desc")] - [:ul.team-features - [:li.feature - [:span.icon i/file-html] - [:p.feature-txt (tr "onboarding.team-modal.create-team-feature-1")]] - [:li.feature - [:span.icon i/pointer-inner] - [:p.feature-txt (tr "onboarding.team-modal.create-team-feature-2")]] - [:li.feature - [:span.icon i/tree] - [:p.feature-txt (tr "onboarding.team-modal.create-team-feature-3")]] - [:li.feature - [:span.icon i/user] - [:p.feature-txt (tr "onboarding.team-modal.create-team-feature-4")]] - [:li.feature - [:span.icon i/tick] - [:p.feature-txt (tr "onboarding.team-modal.create-team-feature-5")]]]]))) + [:div {:class (stl/css :modal-right)} + [:h2 {:class (stl/css :modal-subtitle)} + (tr "onboarding.team-modal.create-team")] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.team-modal.create-team-desc")] + [:ul {:class (stl/css :team-features)} + [:li {:class (stl/css :feature)} + [:span {:class (stl/css :icon)} i/document-refactor] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.team-modal.create-team-feature-1")]] + [:li {:class (stl/css :feature)} + [:span {:class (stl/css :icon)} i/move-refactor] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.team-modal.create-team-feature-2")]] + [:li {:class (stl/css :feature)} + [:span {:class (stl/css :icon)} i/tree-refactor] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.team-modal.create-team-feature-3")]] + [:li {:class (stl/css :feature)} + [:span {:class (stl/css :icon)} i/user-refactor] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.team-modal.create-team-feature-4")]] + [:li {:class (stl/css :feature)} + [:span {:class (stl/css :icon)} i/tick-refactor] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.team-modal.create-team-feature-5")]]]]) (mf/defc onboarding-team-modal {::mf/register modal/components ::mf/register-as :onboarding-team} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - form (fm/use-form :spec ::team-form + (let [form (fm/use-form :spec ::team-form :initial {} :validators [(fm/validate-not-empty :name (tr "auth.name.not-all-space")) (fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))]) @@ -109,76 +82,43 @@ teams (mf/deref refs/teams)] - (if new-css-system - (if (< (count teams) 2) - [:div {:class (stl/css :modal-overlay)} - [:div.animated.fadeIn {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-left)} - [:div {:class (stl/css :first-block)} - [:h2 {:class (stl/css :modal-title)} - (tr "onboarding.team-modal.create-team")] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.choice.team-up.create-team-desc")] - [:& fm/form {:form form - :class (stl/css :modal-form) - :on-submit on-submit} + (if (< (count teams) 2) + [:div {:class (stl/css :modal-overlay)} + [:div.animated.fadeIn {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-left)} + [:div {:class (stl/css :first-block)} + [:h2 {:class (stl/css :modal-title)} + (tr "onboarding.team-modal.create-team")] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.choice.team-up.create-team-desc")] + [:& fm/form {:form form + :class (stl/css :modal-form) + :on-submit on-submit} - [:& fm/input {:type "text" - :class (stl/css :team-name-input) - :name :name - :placeholder "Team name" - :label (tr "onboarding.choice.team-up.create-team-placeholder")}] - - [:div {:class (stl/css :action-buttons)} - [:& fm/submit-button* - {:className (stl/css :accept-button) - :label (tr "onboarding.choice.team-up.continue-creating-team")}]]]] - [:div {:class (stl/css :second-block)} - [:h2 {:class (stl/css :modal-title)} - (tr "onboarding.choice.team-up.start-without-a-team")] - [:p {:class (stl/css :modal-text)} - (tr "onboarding.choice.team-up.start-without-a-team-description")] - - [:div {:class (stl/css :action-buttons)} - [:button {:class (stl/css :accept-button) - :on-click on-skip} - (tr "onboarding.choice.team-up.continue-without-a-team")]]]] - [:& team-modal-right] - [:div {:class (stl/css :paginator)} "1/2"]]] - - (st/emit! (modal/hide))) - - - (if (< (count teams) 2) - - [:div.modal-overlay - [:div.modal-container.onboarding-team.animated.fadeIn - [:div.team-left - [:h2.title (tr "onboarding.team-modal.create-team")] - [:p.info (tr "onboarding.choice.team-up.create-team-desc")] - [:& fm/form {:form form - :on-submit on-submit} - [:& fm/input {:type "text" - :name :name - :label (tr "onboarding.choice.team-up.create-team-placeholder")}] + [:& fm/input {:type "text" + :class (stl/css :team-name-input) + :name :name + :placeholder "Team name" + :label (tr "onboarding.choice.team-up.create-team-placeholder")}] + [:div {:class (stl/css :action-buttons)} [:& fm/submit-button* - {:label (tr "onboarding.choice.team-up.continue-creating-team")}]] + {:className (stl/css :accept-button) + :label (tr "onboarding.choice.team-up.continue-creating-team")}]]]] + [:div {:class (stl/css :second-block)} + [:h2 {:class (stl/css :modal-title)} + (tr "onboarding.choice.team-up.start-without-a-team")] + [:p {:class (stl/css :modal-text)} + (tr "onboarding.choice.team-up.start-without-a-team-description")] - [:h2.title (tr "onboarding.choice.team-up.start-without-a-team")] - [:p.info (tr "onboarding.choice.team-up.start-without-a-team-description")] + [:div {:class (stl/css :action-buttons)} + [:button {:class (stl/css :accept-button) + :on-click on-skip} + (tr "onboarding.choice.team-up.continue-without-a-team")]]]] + [:& team-modal-right] + [:div {:class (stl/css :paginator)} "1/2"]]] - [:div - [:button.btn-primary.btn-large {:on-click on-skip} (tr "onboarding.choice.team-up.continue-without-a-team")]]] - [:& team-modal-right] - [:div.paginator "1/2"] - - [:img.deco.square {:src "images/deco-square.svg" :border "0"}] - [:img.deco.circle {:src "images/deco-circle.svg" :border "0"}] - [:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}] - [:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]] - - (st/emit! (modal/hide)))))) + (st/emit! (modal/hide))))) (defn get-available-roles [] @@ -197,8 +137,7 @@ {::mf/register modal/components ::mf/register-as :onboarding-team-invitations} [{:keys [name] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - initial (mf/use-memo (constantly + (let [initial (mf/use-memo (constantly {:role "editor" :name name})) form (fm/use-form :spec ::invite-form @@ -265,96 +204,48 @@ (on-invite-now form) (on-invite-later form)))))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div.animated.fadeIn {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-left)} - [:h2 {:class (stl/css :modal-title)} (tr "onboarding.choice.team-up.invite-members")] - [:p {:class (stl/css :modal-text)} (tr "onboarding.choice.team-up.invite-members-info")] + [:div {:class (stl/css :modal-overlay)} + [:div.animated.fadeIn {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-left)} + [:h2 {:class (stl/css :modal-title)} (tr "onboarding.choice.team-up.invite-members")] + [:p {:class (stl/css :modal-text)} (tr "onboarding.choice.team-up.invite-members-info")] - [:div {:class (stl/css :modal-form)} - [:& fm/form {:form form - :on-submit on-submit} - [:div {:class (stl/css :role-select)} - [:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")] - [:& fm/select {:name :role :options roles}]] + [:div {:class (stl/css :modal-form)} + [:& fm/form {:form form + :on-submit on-submit} + [:div {:class (stl/css :role-select)} + [:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")] + [:& fm/select {:name :role :options roles}]] - [:div {:class (stl/css :invitation-row)} - [:& fm/multi-input {:type "email" - :name :emails - :auto-focus? true - :trim true - :valid-item-fn us/parse-email - :caution-item-fn #{} - :label (tr "modals.invite-member.emails") - :on-submit on-submit}]]] + [:div {:class (stl/css :invitation-row)} + [:& fm/multi-input {:type "email" + :name :emails + :auto-focus? true + :trim true + :valid-item-fn us/parse-email + :caution-item-fn #{} + :label (tr "modals.invite-member.emails") + :on-submit on-submit}]]] - [:div {:class (stl/css :action-buttons)} - [:button {:class (stl/css :back-button) - :on-click #(st/emit! (modal/show {:type :onboarding-team}) - (ptk/event ::ev/event {::ev/name "invite-members-back" - ::ev/origin "onboarding" - :name name - :step 2}))} - (tr "labels.back")] + [:div {:class (stl/css :action-buttons)} + [:button {:class (stl/css :back-button) + :on-click #(st/emit! (modal/show {:type :onboarding-team}) + (ptk/event ::ev/event {::ev/name "invite-members-back" + ::ev/origin "onboarding" + :name name + :step 2}))} + (tr "labels.back")] - [:& fm/submit-button* - {:className (stl/css :accept-button) - :label - (if (> (count emails) 0) - (tr "onboarding.choice.team-up.create-team-and-invite") - (tr "onboarding.choice.team-up.create-team-without-invite"))}]] - [:div {:class (stl/css :modal-hint)} - (tr "onboarding.choice.team-up.create-team-and-send-invites-description")]]] + [:& fm/submit-button* + {:className (stl/css :accept-button) + :label + (if (> (count emails) 0) + (tr "onboarding.choice.team-up.create-team-and-invite") + (tr "onboarding.choice.team-up.create-team-without-invite"))}]] + [:div {:class (stl/css :modal-hint)} + (tr "onboarding.choice.team-up.create-team-and-send-invites-description")]]] - [:& team-modal-right] - [:div {:class (stl/css :paginator)} "2/2"]]] - - - - [:div.modal-overlay - [:div.modal-container.onboarding-team-members.animated.fadeIn - [:div.team-left - [:h2.title (tr "onboarding.choice.team-up.invite-members")] - [:p.info (tr "onboarding.choice.team-up.invite-members-info")] - - [:& fm/form {:form form - :on-submit on-submit} - [:div.invite-row - [:div.role-wrapper - [:span.rol (tr "onboarding.choice.team-up.roles")] - [:& fm/select {:name :role :options roles}]] - - [:& fm/multi-input {:type "email" - :name :emails - :auto-focus? true - :trim true - :valid-item-fn us/parse-email - :caution-item-fn #{} - :on-submit on-submit - :label (tr "modals.invite-member.emails")}]] - - [:div.buttons - [:button.btn-secondary.btn-large - {:on-click #(st/emit! (modal/show {:type :onboarding-team}) - (ptk/event ::ev/event {::ev/name "invite-members-back" - ::ev/origin "onboarding" - :name name - :step 2}))} - (tr "labels.back")] - [:& fm/submit-button* - {:label - (if (> (count emails) 0) - (tr "onboarding.choice.team-up.create-team-and-send-invites") - (tr "onboarding.choice.team-up.create-team-without-inviting"))}]] - [:div.skip-action - (tr "onboarding.choice.team-up.create-team-and-send-invites-description")]]] - [:& team-modal-right] - [:div.paginator "2/2"] - - [:img.deco.square {:src "images/deco-square.svg" :border "0"}] - [:img.deco.circle {:src "images/deco-circle.svg" :border "0"}] - [:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}] - [:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]))) + [:& team-modal-right] + [:div {:class (stl/css :paginator)} "2/2"]]])) diff --git a/frontend/src/app/main/ui/settings/access_tokens.cljs b/frontend/src/app/main/ui/settings/access_tokens.cljs index a044455aed..5ca78226b8 100644 --- a/frontend/src/app/main/ui/settings/access_tokens.cljs +++ b/frontend/src/app/main/ui/settings/access_tokens.cljs @@ -14,7 +14,6 @@ [app.main.store :as st] [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -51,8 +50,7 @@ {::mf/register modal/components ::mf/register-as :access-token} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - form (fm/use-form + (let [form (fm/use-form :initial initial-data :spec ::access-token-form :validators [name-validator @@ -107,176 +105,96 @@ :content (tr "dashboard.access-tokens.copied-success") :timeout 1000}))))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:& fm/form {:form form :on-submit on-submit} + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:& fm/form {:form form :on-submit on-submit} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} (tr "modals.create-access-token.title")] + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} (tr "modals.create-access-token.title")] - [:button {:class (stl/css :modal-close-btn) - :on-click on-close} i/close-refactor]] + [:button {:class (stl/css :modal-close-btn) + :on-click on-close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "text" - :auto-focus? true - :form form - :name :name - :disabled @created? - :label (tr "modals.create-access-token.name.label") - :show-success? true - :placeholder (tr "modals.create-access-token.name.placeholder")}]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "text" + :auto-focus? true + :form form + :name :name + :disabled @created? + :label (tr "modals.create-access-token.name.label") + :show-success? true + :placeholder (tr "modals.create-access-token.name.placeholder")}]] - [:div {:class (stl/css :fields-row)} - [:div {:class (stl/css :select-title)} (tr "modals.create-access-token.expiration-date.label")] - [:& fm/select {:options [{:label (tr "dashboard.access-tokens.expiration-never") :value "never" :key "never"} - {:label (tr "dashboard.access-tokens.expiration-30-days") :value "720h" :key "720h"} - {:label (tr "dashboard.access-tokens.expiration-60-days") :value "1440h" :key "1440h"} - {:label (tr "dashboard.access-tokens.expiration-90-days") :value "2160h" :key "2160h"} - {:label (tr "dashboard.access-tokens.expiration-180-days") :value "4320h" :key "4320h"}] - :default "never" - :disabled @created? - :name :expiration-date}] - (when @created? - [:span.token-created-info - (if (:expires-at created) - (tr "dashboard.access-tokens.token-will-expire" (dt/format-date-locale (:expires-at created) {:locale locale})) - (tr "dashboard.access-tokens.token-will-not-expire"))])] + [:div {:class (stl/css :fields-row)} + [:div {:class (stl/css :select-title)} (tr "modals.create-access-token.expiration-date.label")] + [:& fm/select {:options [{:label (tr "dashboard.access-tokens.expiration-never") :value "never" :key "never"} + {:label (tr "dashboard.access-tokens.expiration-30-days") :value "720h" :key "720h"} + {:label (tr "dashboard.access-tokens.expiration-60-days") :value "1440h" :key "1440h"} + {:label (tr "dashboard.access-tokens.expiration-90-days") :value "2160h" :key "2160h"} + {:label (tr "dashboard.access-tokens.expiration-180-days") :value "4320h" :key "4320h"}] + :default "never" + :disabled @created? + :name :expiration-date}] + (when @created? + [:span.token-created-info + (if (:expires-at created) + (tr "dashboard.access-tokens.token-will-expire" (dt/format-date-locale (:expires-at created) {:locale locale})) + (tr "dashboard.access-tokens.token-will-not-expire"))])] - [:div {:class (stl/css :fields-row)} - (when @created? - [:div {:class (stl/css :custon-input-wrapper)} - [:input {:type "text" - :value (:token created "") - :class (stl/css :custom-input-token) - :placeholder (tr "modals.create-access-token.token") - :read-only true}] - [:button {:title (tr "modals.create-access-token.copy-token") - :class (stl/css :copy-btn) - :on-click copy-token} - i/clipboard-refactor]]) - #_(when @created? + [:div {:class (stl/css :fields-row)} + (when @created? + [:div {:class (stl/css :custon-input-wrapper)} + [:input {:type "text" + :value (:token created "") + :class (stl/css :custom-input-token) + :placeholder (tr "modals.create-access-token.token") + :read-only true}] + [:button {:title (tr "modals.create-access-token.copy-token") + :class (stl/css :copy-btn) + :on-click copy-token} + i/clipboard-refactor]]) + #_(when @created? [:button {:class (stl/css :copy-btn) :title (tr "modals.create-access-token.copy-token") :on-click copy-token} - [:span {:class (stl/css :token-value)}(:token created "")] + [:span {:class (stl/css :token-value)} (:token created "")] [:span {:class (stl/css :icon)} i/clipboard-refactor]])]] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} - (if @created? - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.close") - :on-click #(modal/hide!)}] - [:* - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.cancel") - :on-click #(modal/hide!)}] - [:> fm/submit-button* - {:label (tr "modals.create-access-token.submit-label")}]])]]]]] - - - [:div.modal-overlay - [:div.modal-container.access-tokens-modal - [:& fm/form {:form form :on-submit on-submit} - - [:div.modal-header - [:div.modal-header-title - [:h2 (tr "modals.create-access-token.title")]] - - [:div.modal-close-button - {:on-click on-close} i/close]] - - [:div.modal-content.generic-form - [:div.fields-container - [:div.fields-row - [:& fm/input {:type "text" - :auto-focus? true - :form form - :name :name - :disabled @created? - :label (tr "modals.create-access-token.name.label") - :placeholder (tr "modals.create-access-token.name.placeholder")}]] - - [:div.fields-row - [:& fm/select {:options [{:label (tr "dashboard.access-tokens.expiration-never") :value "never" :key "never"} - {:label (tr "dashboard.access-tokens.expiration-30-days") :value "720h" :key "720h"} - {:label (tr "dashboard.access-tokens.expiration-60-days") :value "1440h" :key "1440h"} - {:label (tr "dashboard.access-tokens.expiration-90-days") :value "2160h" :key "2160h"} - {:label (tr "dashboard.access-tokens.expiration-180-days") :value "4320h" :key "4320h"}] - :label (tr "modals.create-access-token.expiration-date.label") - :default "never" - :disabled @created? - :name :expiration-date}] - (when @created? - [:span.token-created-info - (if (:expires-at created) - (tr "dashboard.access-tokens.token-will-expire" (dt/format-date-locale (:expires-at created) {:locale locale})) - (tr "dashboard.access-tokens.token-will-not-expire"))])] - - [:div.fields-row.access-token-created - (when @created? - [:div.custom-input.with-icon - [:input {:type "text" - :value (:token created "") - :placeholder (tr "modals.create-access-token.token") - :read-only true}] - [:button.help-icon {:title (tr "modals.create-access-token.copy-token") - :on-click copy-token} - i/copy]])]]] - - [:div.modal-footer - [:div.action-buttons - (if @created? - [:input.cancel-button - {:type "button" - :value (tr "labels.close") - :on-click #(modal/hide!)}] - [:* - [:input.cancel-button - {:type "button" - :value (tr "labels.cancel") - :on-click #(modal/hide!)}] - [:> fm/submit-button* - {:label (tr "modals.create-access-token.submit-label")}]])]]]]]))) + (if @created? + [:input {:class (stl/css :cancel-button) + :type "button" + :value (tr "labels.close") + :on-click #(modal/hide!)}] + [:* + [:input {:class (stl/css :cancel-button) + :type "button" + :value (tr "labels.cancel") + :on-click #(modal/hide!)}] + [:> fm/submit-button* + {:label (tr "modals.create-access-token.submit-label")}]])]]]]])) (mf/defc access-tokens-hero [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-click (mf/use-fn #(st/emit! (modal/show :access-token {})))] - (if new-css-system - [:div {:class (stl/css :access-tokens-hero-container)} - [:div {:class (stl/css :access-tokens-hero)} - [:div {:class (stl/css :desc)} - [:h2 (tr "dashboard.access-tokens.personal")] - [:p (tr "dashboard.access-tokens.personal.description")]] + (let [on-click (mf/use-fn #(st/emit! (modal/show :access-token {})))] + [:div {:class (stl/css :access-tokens-hero-container)} + [:div {:class (stl/css :access-tokens-hero)} + [:div {:class (stl/css :desc)} + [:h2 (tr "dashboard.access-tokens.personal")] + [:p (tr "dashboard.access-tokens.personal.description")]] - [:button - {:class (stl/css :btn-primary) - :on-click on-click} - [:span (tr "dashboard.access-tokens.create")]]]] - - ;; OLD - [:div.access-tokens-hero-container - [:div.access-tokens-hero - [:div.desc - [:h2 (tr "dashboard.access-tokens.personal")] - [:p (tr "dashboard.access-tokens.personal.description")]] - - [:button.btn-primary - {:on-click on-click} - [:span (tr "dashboard.access-tokens.create")]]]]))) + [:button + {:class (stl/css :btn-primary) + :on-click on-click} + [:span (tr "dashboard.access-tokens.create")]]]])) (mf/defc access-token-actions [{:keys [on-delete]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - local (mf/use-state {:menu-open false}) + (let [local (mf/use-state {:menu-open false}) show? (:menu-open @local) options (mf/with-memo [on-delete] [{:option-name (tr "labels.delete") @@ -302,47 +220,25 @@ (dom/stop-propagation event) (on-menu-click event))))] - (if new-css-system - [:div - {:class (stl/css :icon) - :tab-index "0" - :ref menu-ref - :on-click on-menu-click - :on-key-down on-keydown} - i/actions - [:& context-menu-a11y - {:on-close on-menu-close - :show show? - :fixed? true - :min-width? true - :top "auto" - :left "auto" - :options options}]] - - ;; OLD - [:div.icon - {:tab-index "0" - :ref menu-ref - :on-click on-menu-click - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/stop-propagation event) - (on-menu-click event)))} - i/actions - [:& context-menu-a11y - {:on-close on-menu-close - :show show? - :fixed? true - :min-width? true - :top "auto" - :left "auto" - :options options}]]))) + [:div {:class (stl/css :icon) + :tab-index "0" + :ref menu-ref + :on-click on-menu-click + :on-key-down on-keydown} + i/actions + [:& context-menu-a11y + {:on-close on-menu-close + :show show? + :fixed? true + :min-width? true + :top "auto" + :left "auto" + :options options}]])) (mf/defc access-token-item {::mf/wrap [mf/memo]} [{:keys [token] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - locale (mf/deref i18n/locale) + (let [locale (mf/deref i18n/locale) expires-at (:expires-at token) expires-txt (some-> expires-at (dt/format-date-locale {:locale locale})) expired? (and (some? expires-at) (> (dt/now) expires-at)) @@ -366,66 +262,36 @@ :accept-label (tr "modals.delete-acces-token.accept") :on-accept delete-fn}))))] - (if new-css-system - [:div {:class (stl/css :table-row)} - [:div {:class (stl/css :table-field :name)} - (str (:name token))] + [:div {:class (stl/css :table-row)} + [:div {:class (stl/css :table-field :name)} + (str (:name token))] - [:div {:class (stl/css :table-field :expiration-date)} - [:span {:class (stl/css-case :expired expired? :content true)} - (cond - (nil? expires-at) (tr "dashboard.access-tokens.no-expiration") - expired? (tr "dashboard.access-tokens.expired-on" expires-txt) - :else (tr "dashboard.access-tokens.expires-on" expires-txt))]] - [:div {:class (stl/css :table-field :actions)} - [:& access-token-actions - {:on-delete on-delete}]]] - - ;; OLD - [:div.table-row - [:div.table-field.name - (str (:name token))] - [:div.table-field.expiration-date - [:span.content {:class (when expired? "expired")} - (cond - (nil? expires-at) (tr "dashboard.access-tokens.no-expiration") - expired? (tr "dashboard.access-tokens.expired-on" expires-txt) - :else (tr "dashboard.access-tokens.expires-on" expires-txt))]] - [:div.table-field.actions - [:& access-token-actions - {:on-delete on-delete}]]]))) + [:div {:class (stl/css :table-field :expiration-date)} + [:span {:class (stl/css-case :expired expired? :content true)} + (cond + (nil? expires-at) (tr "dashboard.access-tokens.no-expiration") + expired? (tr "dashboard.access-tokens.expired-on" expires-txt) + :else (tr "dashboard.access-tokens.expires-on" expires-txt))]] + [:div {:class (stl/css :table-field :actions)} + [:& access-token-actions + {:on-delete on-delete}]]])) (mf/defc access-tokens-page [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - tokens (mf/deref tokens-ref)] + (let [tokens (mf/deref tokens-ref)] (mf/with-effect [] (dom/set-html-title (tr "title.settings.access-tokens")) (st/emit! (du/fetch-access-tokens))) - (if new-css-system - [:div {:class (stl/css :dashboard-access-tokens)} - [:div - [:& access-tokens-hero] - (if (empty? tokens) - [:div {:class (stl/css :access-tokens-empty)} - [:div (tr "dashboard.access-tokens.empty.no-access-tokens")] - [:div (tr "dashboard.access-tokens.empty.add-one")]] - [:div {:class (stl/css :dashboard-table)} - [:div {:class (stl/css :table-rows)} - (for [token tokens] - [:& access-token-item {:token token :key (:id token)}])]])]] - - ;; OLD - [:div.dashboard-access-tokens - [:div - [:& access-tokens-hero] - (if (empty? tokens) - [:div.access-tokens-empty - [:div (tr "dashboard.access-tokens.empty.no-access-tokens")] - [:div (tr "dashboard.access-tokens.empty.add-one")]] - [:div.dashboard-table - [:div.table-rows - (for [token tokens] - [:& access-token-item {:token token :key (:id token)}])]])]]))) + [:div {:class (stl/css :dashboard-access-tokens)} + [:div + [:& access-tokens-hero] + (if (empty? tokens) + [:div {:class (stl/css :access-tokens-empty)} + [:div (tr "dashboard.access-tokens.empty.no-access-tokens")] + [:div (tr "dashboard.access-tokens.empty.add-one")]] + [:div {:class (stl/css :dashboard-table)} + [:div {:class (stl/css :table-rows)} + (for [token tokens] + [:& access-token-item {:token token :key (:id token)}])]])]])) diff --git a/frontend/src/app/main/ui/settings/access_tokens.scss b/frontend/src/app/main/ui/settings/access_tokens.scss index 2e9b8ef178..84b46fd7cf 100644 --- a/frontend/src/app/main/ui/settings/access_tokens.scss +++ b/frontend/src/app/main/ui/settings/access_tokens.scss @@ -12,95 +12,95 @@ font-size: $fs-16; margin-top: $s-20; width: $s-800; +} - .table-header { - color: $df-secondary; - display: grid; - font-size: $fs-12; - grid-template-columns: 43% 1fr $s-108 $s-12; - height: $s-40; - max-width: $s-1000; - padding: 0 $s-16; - text-transform: uppercase; - width: 100%; +.table-header { + color: $df-secondary; + display: grid; + font-size: $fs-12; + grid-template-columns: 43% 1fr $s-108 $s-12; + height: $s-40; + max-width: $s-1000; + padding: 0 $s-16; + text-transform: uppercase; + width: 100%; +} + +.table-rows { + color: $db-secondary; + display: flex; + flex-direction: column; + margin-top: $s-16; + max-width: $s-1000; + padding-top: 0; + width: 100%; +} + +.table-row { + align-items: center; + background-color: $db-tertiary; + border-radius: $br-8; + color: $df-primary; + display: grid; + font-size: $fs-14; + grid-template-columns: 1fr 43% $s-12; + height: fit-content; + min-height: $s-40; + padding: 0 $s-16; + width: 100%; + + &:not(:first-child) { + margin-top: $s-8; + } +} + +.table-field { + display: flex; + align-items: center; + + .icon { + padding-left: $s-12; + cursor: pointer; } - .table-rows { - color: $db-secondary; - display: flex; - flex-direction: column; - margin-top: $s-16; - max-width: $s-1000; - padding-top: 0; - width: 100%; - } - - .table-row { - align-items: center; - background-color: $db-tertiary; - border-radius: $br-8; + &.name { + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; color: $df-primary; - display: grid; - font-size: $fs-14; - grid-template-columns: 1fr 43% $s-12; - height: fit-content; - min-height: $s-40; - padding: 0 $s-16; - width: 100%; - - &:not(:first-child) { - margin-top: $s-8; - } + display: -webkit-box; + max-width: $s-480; + overflow: hidden; + text-overflow: ellipsis; } - .table-field { - display: flex; - align-items: center; + &.expiration-date { + color: $df-secondary; + font-size: $fs-14; - .icon { - padding-left: $s-12; - cursor: pointer; - } - - &.name { - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - color: $df-primary; - display: -webkit-box; - max-width: $s-480; - overflow: hidden; - text-overflow: ellipsis; - } - - &.expiration-date { - color: $df-secondary; - font-size: $fs-14; - - .content { - padding: $s-2 $s-6; - &.expired { - background-color: var(--warning-color); - border-radius: $br-4; - color: $db-secondary; - } + .content { + padding: $s-2 $s-6; + &.expired { + background-color: var(--warning-color); + border-radius: $br-4; + color: $db-secondary; } } - &.access-token-created { - word-break: break-all; - } - - &.actions { - position: relative; - } + } + &.access-token-created { + word-break: break-all; } - svg { - width: $s-12; - height: $s-12; - fill: $df-primary; + &.actions { + position: relative; } } +svg { + width: $s-12; + height: $s-12; + fill: $df-primary; +} + .dashboard-access-tokens { display: flex; flex-direction: column; diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs index 08ab6ea6f7..37d4f54c7f 100644 --- a/frontend/src/app/main/ui/settings/change_email.cljs +++ b/frontend/src/app/main/ui/settings/change_email.cljs @@ -16,7 +16,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.i18n :as i18n :refer [tr]] @@ -76,8 +75,7 @@ {::mf/register modal/components ::mf/register-as :change-email} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - profile (mf/deref refs/profile) + (let [profile (mf/deref refs/profile) form (fm/use-form :spec ::email-change-form :validators [email-equality] :initial profile) @@ -99,82 +97,44 @@ (when (and different-emails-error? (= email-1 email-2)) (swap! form d/dissoc-in [:errors :email-2])))))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:& fm/form {:form form - :on-submit on-submit} + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:& fm/form {:form form + :on-submit on-submit} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title) - :data-test "change-email-title"} - (tr "modals.change-email.title")] - [:button {:class (stl/css :modal-close-btn) - :on-click on-close} i/close-refactor]] + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title) + :data-test "change-email-title"} + (tr "modals.change-email.title")] + [:button {:class (stl/css :modal-close-btn) + :on-click on-close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:& msgs/inline-banner - {:type :info - :content (tr "modals.change-email.info" (:email profile))}] + [:div {:class (stl/css :modal-content)} + [:& msgs/inline-banner + {:type :info + :content (tr "modals.change-email.info" (:email profile))}] - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "email" - :name :email-1 - :label (tr "modals.change-email.new-email") - :trim true - :show-success? true - :on-change-value on-email-change}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "email" + :name :email-1 + :label (tr "modals.change-email.new-email") + :trim true + :show-success? true + :on-change-value on-email-change}]] - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "email" - :name :email-2 - :label (tr "modals.change-email.confirm-email") - :trim true - :show-success? true - :on-change-value on-email-change}]]] + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "email" + :name :email-2 + :label (tr "modals.change-email.confirm-email") + :trim true + :show-success? true + :on-change-value on-email-change}]]] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons) - :data-test "change-email-submit"} - [:> fm/submit-button* - {:label (tr "modals.change-email.submit")}]]]]]] - - - [:div.modal-overlay - [:div.modal-container.change-email-modal.form-container - [:& fm/form {:form form - :on-submit on-submit} - - [:div.modal-header - [:div.modal-header-title - [:h2 {:data-test "change-email-title"} - (tr "modals.change-email.title")]] - [:div.modal-close-button - {:on-click on-close} i/close]] - - [:div.modal-content - [:& msgs/inline-banner - {:type :info - :content (tr "modals.change-email.info" (:email profile))}] - - [:div.fields-container - [:div.fields-row - [:& fm/input {:type "email" - :name :email-1 - :label (tr "modals.change-email.new-email") - :trim true - :on-change-value on-email-change}]] - [:div.fields-row - [:& fm/input {:type "email" - :name :email-2 - :label (tr "modals.change-email.confirm-email") - :trim true - :on-change-value on-email-change}]]]] - - [:div.modal-footer - [:div.action-buttons {:data-test "change-email-submit"} - [:> fm/submit-button* - {:label (tr "modals.change-email.submit")}]]]]]]) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons) + :data-test "change-email-submit"} + [:> fm/submit-button* + {:label (tr "modals.change-email.submit")}]]]]]] )) diff --git a/frontend/src/app/main/ui/settings/change_email.scss b/frontend/src/app/main/ui/settings/change_email.scss index 6b6b760c99..97da12aeca 100644 --- a/frontend/src/app/main/ui/settings/change_email.scss +++ b/frontend/src/app/main/ui/settings/change_email.scss @@ -8,46 +8,50 @@ .modal-overlay { @extend .modal-overlay-base; - .modal-container { - @extend .modal-container-base; - min-width: $s-408; - border: $s-1 solid var(--modal-border-color); - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } +} - .modal-content { - @include flexColumn; - @include titleTipography; - gap: $s-24; - margin-bottom: $s-24; +.modal-container { + @extend .modal-container-base; + min-width: $s-408; + border: $s-1 solid var(--modal-border-color); +} - .fields-row { - @include flexColumn; - .select-title { - @include titleTipography; - color: var(--modal-title-foreground-color); - } - } - } +.modal-header { + margin-bottom: $s-24; +} - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - button { - @extend .modal-accept-btn; - } - .cancel-button { - @extend .modal-cancel-btn; - } - } - } +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include flexColumn; + @include titleTipography; + gap: $s-24; + margin-bottom: $s-24; +} + +.fields-row { + @include flexColumn; +} + +.select-title { + @include titleTipography; + color: var(--modal-title-foreground-color); +} + +.action-buttons { + @extend .modal-action-btns; + button { + @extend .modal-accept-btn; } } + +.cancel-button { + @extend .modal-cancel-btn; +} diff --git a/frontend/src/app/main/ui/settings/delete_account.cljs b/frontend/src/app/main/ui/settings/delete_account.cljs index a9c26b7305..2eddcca231 100644 --- a/frontend/src/app/main/ui/settings/delete_account.cljs +++ b/frontend/src/app/main/ui/settings/delete_account.cljs @@ -11,7 +11,6 @@ [app.main.data.modal :as modal] [app.main.data.users :as du] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.i18n :as i18n :refer [tr]] @@ -29,8 +28,7 @@ {::mf/register modal/components ::mf/register-as :delete-account} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-close + (let [on-close (mf/use-callback #(st/emit! (modal/hide))) on-accept @@ -39,52 +37,28 @@ (du/request-account-deletion (with-meta {} {:on-error on-error}))))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} + [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} (tr "modals.delete-account.title")] - [:button {:class (stl/css :modal-close-btn) - :on-click on-close} i/close-refactor]] + [:h2 {:class (stl/css :modal-title)} (tr "modals.delete-account.title")] + [:button {:class (stl/css :modal-close-btn) + :on-click on-close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:& msgs/inline-banner - {:type :warning - :content (tr "modals.delete-account.info")}]] + [:div {:class (stl/css :modal-content)} + [:& msgs/inline-banner + {:type :warning + :content (tr "modals.delete-account.info")}]] - [:div {:class (stl/css :modal-footer)} - [:div {:class (stl/css :action-buttons)} - [:button {:class (stl/css :cancel-button) - :on-click on-close} - (tr "modals.delete-account.cancel")] - [:button {:class (stl/css-case :accept-button true - :danger true) - :on-click on-accept - :data-test "delete-account-btn"} - (tr "modals.delete-account.confirm")]]]]] - - - - [:div.modal-overlay - [:div.modal-container.change-email-modal - [:div.modal-header - [:div.modal-header-title - [:h2 (tr "modals.delete-account.title")]] - [:div.modal-close-button - {:on-click on-close} i/close]] - - [:div.modal-content - [:& msgs/inline-banner - {:type :warning - :content (tr "modals.delete-account.info")}]] - - [:div.modal-footer - [:div.action-buttons - [:button.btn-danger.btn-large {:on-click on-accept - :data-test "delete-account-btn"} - (tr "modals.delete-account.confirm")] - [:button.btn-secondary.btn-large {:on-click on-close} - (tr "modals.delete-account.cancel")]]]]]))) + [:div {:class (stl/css :modal-footer)} + [:div {:class (stl/css :action-buttons)} + [:button {:class (stl/css :cancel-button) + :on-click on-close} + (tr "modals.delete-account.cancel")] + [:button {:class (stl/css-case :accept-button true + :danger true) + :on-click on-accept + :data-test "delete-account-btn"} + (tr "modals.delete-account.confirm")]]]]])) diff --git a/frontend/src/app/main/ui/settings/delete_account.scss b/frontend/src/app/main/ui/settings/delete_account.scss index e12ff29a8f..33e72dd4ac 100644 --- a/frontend/src/app/main/ui/settings/delete_account.scss +++ b/frontend/src/app/main/ui/settings/delete_account.scss @@ -8,50 +8,54 @@ .modal-overlay { @extend .modal-overlay-base; - .modal-container { - @extend .modal-container-base; - min-width: $s-408; - border: $s-1 solid var(--modal-border-color); - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } +} - .modal-content { - @include flexColumn; - @include titleTipography; - gap: $s-24; - margin-bottom: $s-24; +.modal-container { + @extend .modal-container-base; + min-width: $s-408; + border: $s-1 solid var(--modal-border-color); +} - .fields-row { - @include flexColumn; - .select-title { - @include titleTipography; - color: var(--modal-title-foreground-color); - } - } - } +.modal-header { + margin-bottom: $s-24; +} - .modal-footer { - .action-buttons { - @extend .modal-action-btns; +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} - .cancel-button { - @extend .modal-cancel-btn; - } - .accept-button { - @extend .modal-accept-btn; - &.danger { - @extend .modal-danger-btn; - } - } - } - } +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include flexColumn; + @include titleTipography; + gap: $s-24; + margin-bottom: $s-24; +} + +.fields-row { + @include flexColumn; +} + +.select-title { + @include titleTipography; + color: var(--modal-title-foreground-color); +} + +.action-buttons { + @extend .modal-action-btns; +} + +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-button { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; } } diff --git a/frontend/src/app/main/ui/viewer/login.cljs b/frontend/src/app/main/ui/viewer/login.cljs index 375066e137..3341fac27c 100644 --- a/frontend/src/app/main/ui/viewer/login.cljs +++ b/frontend/src/app/main/ui/viewer/login.cljs @@ -14,7 +14,6 @@ [app.main.ui.auth.login :refer [login-methods]] [app.main.ui.auth.recovery-request :refer [recovery-request-page]] [app.main.ui.auth.register :refer [register-methods register-validate-form register-success-page]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -27,8 +26,7 @@ {::mf/register modal/components ::mf/register-as :login-register} [_] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - uri (. (. js/document -location) -href) + (let [uri (. (. js/document -location) -href) user-email (mf/use-state "") register-token (mf/use-state "") @@ -71,114 +69,58 @@ (mf/with-effect [] (swap! storage assoc :redirect-url uri)) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} (tr "labels.continue-with-penpot")] - [:button {:class (stl/css :modal-close-btn) - :title (tr "labels.close") - :on-click close} i/close-refactor]] + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} (tr "labels.continue-with-penpot")] + [:button {:class (stl/css :modal-close-btn) + :title (tr "labels.close") + :on-click close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-content)} - (case current-section - :login - [:div {:class (stl/css :form-container)} - [:& login-methods {:on-success-callback success-login :origin :viewer}] - [:div {:class (stl/css :links)} - [:div {:class (stl/css :link-entry)} - [:a {:on-click set-section - :data-value :recovery-request} - (tr "auth.forgot-password")]] - [:div {:class (stl/css :link-entry)} - [:span (tr "auth.register") " "] - [:a {:on-click set-section - :data-value :register} - (tr "auth.register-submit")]]]] + (case current-section + :login + [:div {:class (stl/css :form-container)} + [:& login-methods {:on-success-callback success-login :origin :viewer}] + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry)} + [:a {:on-click set-section + :data-value :recovery-request} + (tr "auth.forgot-password")]] + [:div {:class (stl/css :link-entry)} + [:span (tr "auth.register") " "] + [:a {:on-click set-section + :data-value :register} + (tr "auth.register-submit")]]]] - :register - [:div {:class (stl/css :form-container)} - [:& register-methods {:on-success-callback success-register}] - [:div {:class (stl/css :links)} - [:div {:class (stl/css :link-entry)} - [:span (tr "auth.already-have-account") " "] - [:a {:on-click set-section - :data-value :login} - (tr "auth.login-here")]]]] + :register + [:div {:class (stl/css :form-container)} + [:& register-methods {:on-success-callback success-register}] + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry)} + [:span (tr "auth.already-have-account") " "] + [:a {:on-click set-section + :data-value :login} + (tr "auth.login-here")]]]] - :register-validate - [:div {:class (stl/css :form-container)} - [:& register-validate-form {:params {:token @register-token} - :on-success-callback success-email-sent}] - [:div {:class (stl/css :links)} - [:div {:class (stl/css :link-entry)} - [:a {:on-click set-section - :data-value :register} - (tr "labels.go-back")]]]] - - :recovery-request - [:& recovery-request-page {:go-back-callback go-back-to-login + :register-validate + [:div {:class (stl/css :form-container)} + [:& register-validate-form {:params {:token @register-token} :on-success-callback success-email-sent}] - :email-sent - [:div {:class (stl/css :form-container)} - [:& register-success-page {:params {:email @user-email}}]]) + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry)} + [:a {:on-click set-section + :data-value :register} + (tr "labels.go-back")]]]] - (when main-section - [:div {:class (stl/css :links)} - [:& terms-login]])]]] + :recovery-request + [:& recovery-request-page {:go-back-callback go-back-to-login + :on-success-callback success-email-sent}] + :email-sent + [:div {:class (stl/css :form-container)} + [:& register-success-page {:params {:email @user-email}}]]) - - ;;OLD - [:div.modal-overlay - [:div.modal-container.login-register - [:div.title - [:div.modal-close-button {:on-click close :title (tr "labels.close")} - i/close] - (when main-section - [:h2 (tr "labels.continue-with-penpot")])] - - [:div.modal-bottom.auth-content - - (case current-section - :login - [:div.generic-form.login-form - [:div.form-container - [:& login-methods {:on-success-callback success-login}] - [:div.links - [:div.link-entry - [:a {:on-click #(set-current-section :recovery-request)} - (tr "auth.forgot-password")]] - [:div.link-entry - [:span (tr "auth.register") " "] - [:a {:on-click #(set-current-section :register)} - (tr "auth.register-submit")]]]]] - - :register - [:div.form-container - [:& register-methods {:on-success-callback success-register}] - [:div.links - [:div.link-entry - [:span (tr "auth.already-have-account") " "] - [:a {:on-click #(set-current-section :login)} - (tr "auth.login-here")]]]] - - :register-validate - [:div.form-container - [:& register-validate-form {:params {:token @register-token} - :on-success-callback success-email-sent}] - [:div.links - [:div.link-entry - [:a {:on-click #(set-current-section :register)} - (tr "labels.go-back")]]]] - - :recovery-request - [:& recovery-request-page {:go-back-callback #(set-current-section :login) - :on-success-callback success-email-sent}] - :email-sent - [:div.form-container - [:& register-success-page {:params {:email @user-email}}]])] - - (when main-section - [:div.modal-footer.links - [:& terms-login]])]]))) + (when main-section + [:div {:class (stl/css :links)} + [:& terms-login]])]]])) diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs index 41bd3ed204..0c2769cc90 100644 --- a/frontend/src/app/main/ui/viewer/share_link.cljs +++ b/frontend/src/app/main/ui/viewer/share_link.cljs @@ -18,7 +18,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.select :refer [select]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -40,8 +39,7 @@ ::mf/register-as :share-link ::mf/wrap-props false} [{:keys [file page]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - current-page page + (let [current-page page current-page-id (:id page) slinks (mf/deref refs/share-links) router (mf/deref refs/router) @@ -165,274 +163,151 @@ (reset! confirm* false) (swap! options* assoc :who-comment value))] - (if new-css-system - [:div {:class (stl/css :share-modal)} - [:div {:class (stl/css :share-link-dialog)} - [:div {:class (stl/css :share-link-header)} - [:h2 {:class (stl/css :share-link-title)} - (tr "common.share-link.title")] - [:button {:class (stl/css :modal-close-button) - :on-click on-close - :title (tr "labels.close")} - i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :share-link-section)} - (when (and (not confirm?) (some? current-link)) - [:div {:class (stl/css :custon-input-wrapper)} - [:input {:class (stl/css :input-text) - :type "text" - :value (or current-link "") - :placeholder (tr "common.share-link.placeholder") - :read-only true}] - - [:button {:class (stl/css :copy-button) - :title (tr "viewer.header.share.copy-link") - :on-click copy-link} - i/clipboard-refactor]]) - - [:div {:class (stl/css :hint-wrapper)} - (when (not ^boolean confirm?) - [:div {:class (stl/css :hint)} (tr "common.share-link.permissions-hint")]) - (cond - (true? confirm?) - [:div {:class (stl/css :confirm-dialog)} - [:div {:class (stl/css :description)} - (tr "common.share-link.confirm-deletion-link-description")] - [:div {:class (stl/css :actions)} - [:input {:type "button" - :class (stl/css :button-cancel) - :on-click #(reset! confirm* false) - :value (tr "labels.cancel")}] - [:input {:type "button" - :class (stl/css :button-danger) - :on-click delete-link - :value (tr "common.share-link.destroy-link")}]]] - - (some? current-link) - [:input - {:type "button" - :class (stl/css :button-danger) - :on-click try-delete-link - :value (tr "common.share-link.destroy-link")}] - - :else - [:input - {:type "button" - :class (stl/css :button-active) - :on-click create-link - :value (tr "common.share-link.get-link")}])]] + [:div {:class (stl/css :share-modal)} + [:div {:class (stl/css :share-link-dialog)} + [:div {:class (stl/css :share-link-header)} + [:h2 {:class (stl/css :share-link-title)} + (tr "common.share-link.title")] + [:button {:class (stl/css :modal-close-button) + :on-click on-close + :title (tr "labels.close")} + i/close-refactor]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :share-link-section)} + (when (and (not confirm?) (some? current-link)) + [:div {:class (stl/css :custon-input-wrapper)} + [:input {:class (stl/css :input-text) + :type "text" + :value (or current-link "") + :placeholder (tr "common.share-link.placeholder") + :read-only true}] + [:button {:class (stl/css :copy-button) + :title (tr "viewer.header.share.copy-link") + :on-click copy-link} + i/clipboard-refactor]]) + [:div {:class (stl/css :hint-wrapper)} (when (not ^boolean confirm?) - [:div {:class (stl/css :permissions-section)} - [:button {:class (stl/css :manage-permissions) - :on-click toggle-perms-visibility} - [:span {:class (stl/css-case :icon true - :rotated perms-visible?)} - i/arrow-refactor] - (tr "common.share-link.manage-ops")] + [:div {:class (stl/css :hint)} (tr "common.share-link.permissions-hint")]) + (cond + (true? confirm?) + [:div {:class (stl/css :confirm-dialog)} + [:div {:class (stl/css :description)} + (tr "common.share-link.confirm-deletion-link-description")] + [:div {:class (stl/css :actions)} + [:input {:type "button" + :class (stl/css :button-cancel) + :on-click #(reset! confirm* false) + :value (tr "labels.cancel")}] + [:input {:type "button" + :class (stl/css :button-danger) + :on-click delete-link + :value (tr "common.share-link.destroy-link")}]]] - (when ^boolean perms-visible? - [:* - (let [all-selected? (:all-pages options) - pages (->> (get-in file [:data :pages]) - (map #(get-in file [:data :pages-index %]))) - selected (:pages options)] - [:div {:class (stl/css :view-mode)} - [:div {:class (stl/css :subtitle)} - (tr "common.share-link.permissions-pages")] - [:div {:class (stl/css :items)} - (if (= 1 (count pages)) + (some? current-link) + [:input + {:type "button" + :class (stl/css :button-danger) + :on-click try-delete-link + :value (tr "common.share-link.destroy-link")}] - [:div {:class (stl/css :checkbox-wrapper)} - [:input {:type "checkbox" - :id (dm/str "page-" current-page-id) - :data-page-id (dm/str current-page-id) - :on-change on-mark-checked-page - :checked true}] - [:label {:for (str "page-" current-page-id)} (:name current-page)] - [:span {:class (stl/css-case :checkobox-tick true - :global/checked true)} - i/status-tick-refactor] - [:span (str " " (tr "common.share-link.current-tag"))]] + :else + [:input + {:type "button" + :class (stl/css :button-active) + :on-click create-link + :value (tr "common.share-link.get-link")}])]] - [:* - [:div {:class (stl/css :select-all-row)} - [:div {:class (stl/css :checkbox-wrapper)} - [:label {:for "view-all" - :class (stl/css :select-all-label)} - [:span {:class (stl/css-case :global/checked all-selected?)} - (when all-selected? - i/status-tick-refactor)] - (tr "common.share-link.view-all") - [:input {:type "checkbox" - :id "view-all" - :checked all-selected? - :name "pages-mode" - :on-change on-toggle-all}]]] - [:span {:class (stl/css :count-pages)} - (tr "common.share-link.page-shared" (i18n/c (count selected)))]] + (when (not ^boolean confirm?) + [:div {:class (stl/css :permissions-section)} + [:button {:class (stl/css :manage-permissions) + :on-click toggle-perms-visibility} + [:span {:class (stl/css-case :icon true + :rotated perms-visible?)} + i/arrow-refactor] + (tr "common.share-link.manage-ops")] - [:ul {:class (stl/css :pages-selection)} - (for [{:keys [id name]} pages] - [:li {:class (stl/css :checkbox-wrapper) - :key (dm/str id)} - [:label {:for (dm/str "page-" id)} - [:span {:class (stl/css-case :global/checked (contains? selected id))} - (when (contains? selected id) - i/status-tick-refactor)] - name - (when (= current-page-id id) - [:div {:class (stl/css :current-tag)} (dm/str " " (tr "common.share-link.current-tag"))]) - [:input {:type "checkbox" - :id (dm/str "page-" id) - :data-page-id (dm/str id) - :on-change on-mark-checked-page - :checked (contains? selected id)}]]])]])]]) - - [:div {:class (stl/css :access-mode)} + (when ^boolean perms-visible? + [:* + (let [all-selected? (:all-pages options) + pages (->> (get-in file [:data :pages]) + (map #(get-in file [:data :pages-index %]))) + selected (:pages options)] + [:div {:class (stl/css :view-mode)} [:div {:class (stl/css :subtitle)} - (tr "common.share-link.permissions-can-comment")] - [:div {:class (stl/css :items)} - [:& select - {:class (stl/css :who-comment-select) - :default-value (dm/str (:who-comment options)) - :options [{:value "team" :label (tr "common.share-link.team-members")} - {:value "all" :label (tr "common.share-link.all-users")}] - :on-change on-comment-change}]]] - [:div {:class (stl/css :inspect-mode)} - [:div {:class (stl/css :subtitle)} - (tr "common.share-link.permissions-can-inspect")] - [:div {:class (stl/css :items)} - [:& select - {:class (stl/css :who-inspect-select) - :default-value (dm/str (:who-inspect options)) - :options [{:value "team" :label (tr "common.share-link.team-members")} - {:value "all" :label (tr "common.share-link.all-users")}] - :on-change on-inspect-change}]]]])])]]] - - - ;;OLD - [:div.modal-overlay.transparent.share-modal - [:div.modal-container.share-link-dialog - [:div.modal-content.initial - [:div.title - [:h2 (tr "common.share-link.title")] - [:div.modal-close-button - {:on-click on-close - :title (tr "labels.close")} - i/close]]] - [:div.modal-content - [:div.share-link-section - (when (and (not confirm?) (some? current-link)) - [:div.custom-input.with-icon - [:input {:type "text" - :value (or current-link "") - :placeholder (tr "common.share-link.placeholder") - :read-only true}] - [:div.help-icon {:title (tr "viewer.header.share.copy-link") - :on-click copy-link} - i/copy]]) - [:div.hint-wrapper - (when (not ^boolean confirm?) - [:div.hint (tr "common.share-link.permissions-hint")]) - (cond - (true? confirm?) - [:div.confirm-dialog - [:div.description (tr "common.share-link.confirm-deletion-link-description")] - [:div.actions - [:input.btn-secondary - {:type "button" - :on-click #(reset! confirm* false) - :value (tr "labels.cancel")}] - [:input.btn-danger - {:type "button" - :on-click delete-link - :value (tr "common.share-link.destroy-link")}]]] - - (some? current-link) - [:input.btn-secondary - {:type "button" - :class "primary" - :on-click try-delete-link - :value (tr "common.share-link.destroy-link")}] - - :else - [:input.btn-primary - {:type "button" - :class "primary" - :on-click create-link - :value (tr "common.share-link.get-link")}])]]] - [:div.modal-content.ops-section - [:div.manage-permissions - {:on-click toggle-perms-visibility} - [:span.icon i/picker-hsv] - [:div.title (tr "common.share-link.manage-ops")]] - (when ^boolean perms-visible? - [:* - (let [all-selected? (:all-pages options) - pages (->> (get-in file [:data :pages]) - (map #(get-in file [:data :pages-index %]))) - selected (:pages options)] - [:* - [:div.view-mode - [:div.subtitle - [:span.icon i/play] (tr "common.share-link.permissions-pages")] - [:div.items + [:div {:class (stl/css :items)} (if (= 1 (count pages)) - [:div.input-checkbox.check-primary + + [:div {:class (stl/css :checkbox-wrapper)} [:input {:type "checkbox" :id (dm/str "page-" current-page-id) :data-page-id (dm/str current-page-id) :on-change on-mark-checked-page :checked true}] [:label {:for (str "page-" current-page-id)} (:name current-page)] + [:span {:class (stl/css-case :checkobox-tick true + :global/checked true)} + i/status-tick-refactor] [:span (str " " (tr "common.share-link.current-tag"))]] [:* - [:div.row - [:div.input-checkbox.check-primary - [:input {:type "checkbox" - :id "view-all" - :checked all-selected? - :name "pages-mode" - :on-change on-toggle-all}] - [:label {:for "view-all"} (tr "common.share-link.view-all")]] - [:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]] + [:div {:class (stl/css :select-all-row)} + [:div {:class (stl/css :checkbox-wrapper)} + [:label {:for "view-all" + :class (stl/css :select-all-label)} + [:span {:class (stl/css-case :global/checked all-selected?)} + (when all-selected? + i/status-tick-refactor)] + (tr "common.share-link.view-all") + [:input {:type "checkbox" + :id "view-all" + :checked all-selected? + :name "pages-mode" + :on-change on-toggle-all}]]] - [:ul.pages-selection + [:span {:class (stl/css :count-pages)} + (tr "common.share-link.page-shared" (i18n/c (count selected)))]] + + [:ul {:class (stl/css :pages-selection)} (for [{:keys [id name]} pages] - [:li.input-checkbox.check-primary {:key (dm/str id)} - [:input {:type "checkbox" - :id (dm/str "page-" id) - :data-page-id (dm/str id) - :on-change on-mark-checked-page - :checked (contains? selected id)}] - (if (= current-page-id id) - [:* - [:label {:for (dm/str "page-" id)} name] - [:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]] - [:label {:for (dm/str "page-" id)} name])])]])]]]) - [:div.access-mode - [:div.subtitle - [:span.icon i/chat] - (tr "common.share-link.permissions-can-comment")] - [:div.items - [:select.input-select {:on-change on-comment-change - :value (:who-comment options)} - [:option {:value "team"} (tr "common.share-link.team-members")] - [:option {:value "all"} (tr "common.share-link.all-users")]]]] - [:div.inspect-mode - [:div.subtitle - [:span.icon i/code] - (tr "common.share-link.permissions-can-inspect")] - [:div.items - [:select.input-select {:on-change on-inspect-change - :value (:who-inspect options)} - [:option {:value "team"} (tr "common.share-link.team-members")] - [:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]]))) + [:li {:class (stl/css :checkbox-wrapper) + :key (dm/str id)} + [:label {:for (dm/str "page-" id)} + [:span {:class (stl/css-case :global/checked (contains? selected id))} + (when (contains? selected id) + i/status-tick-refactor)] + name + (when (= current-page-id id) + [:div {:class (stl/css :current-tag)} (dm/str " " (tr "common.share-link.current-tag"))]) + [:input {:type "checkbox" + :id (dm/str "page-" id) + :data-page-id (dm/str id) + :on-change on-mark-checked-page + :checked (contains? selected id)}]]])]])]]) + + [:div {:class (stl/css :access-mode)} + [:div {:class (stl/css :subtitle)} + (tr "common.share-link.permissions-can-comment")] + [:div {:class (stl/css :items)} + [:& select + {:class (stl/css :who-comment-select) + :default-value (dm/str (:who-comment options)) + :options [{:value "team" :label (tr "common.share-link.team-members")} + {:value "all" :label (tr "common.share-link.all-users")}] + :on-change on-comment-change}]]] + [:div {:class (stl/css :inspect-mode)} + [:div {:class (stl/css :subtitle)} + (tr "common.share-link.permissions-can-inspect")] + [:div {:class (stl/css :items)} + [:& select + {:class (stl/css :who-inspect-select) + :default-value (dm/str (:who-inspect options)) + :options [{:value "team" :label (tr "common.share-link.team-members")} + {:value "all" :label (tr "common.share-link.all-users")}] + :on-change on-inspect-change}]]]])])]]])) diff --git a/frontend/src/app/main/ui/workspace/left_header.scss b/frontend/src/app/main/ui/workspace/left_header.scss index 7b34ccb0aa..d527a04e9c 100644 --- a/frontend/src/app/main/ui/workspace/left_header.scss +++ b/frontend/src/app/main/ui/workspace/left_header.scss @@ -19,7 +19,8 @@ height: $s-32; margin-right: $s-4; svg { - height: $s-32; + min-height: $s-32; + width: $s-32; fill: var(--icon-foreground-hover); } } diff --git a/frontend/src/app/main/ui/workspace/libraries.scss b/frontend/src/app/main/ui/workspace/libraries.scss index 6b7825bf6c..8ebf89b741 100644 --- a/frontend/src/app/main/ui/workspace/libraries.scss +++ b/frontend/src/app/main/ui/workspace/libraries.scss @@ -39,9 +39,11 @@ stroke: var(--icon-foreground); } } + .modal-title { @include tabTitleTipography; margin-bottom: $s-16; + color: var(--modal-title-foreground-color); } .modal-content { @@ -161,6 +163,7 @@ .section-list-empty { @include titleTipography; @include flexCenter; + color: var(--empty-message-foreground-color); svg { @extend .button-icon-small; diff --git a/frontend/src/app/main/ui/workspace/nudge.cljs b/frontend/src/app/main/ui/workspace/nudge.cljs index 6e59f46188..868e294fdd 100644 --- a/frontend/src/app/main/ui/workspace/nudge.cljs +++ b/frontend/src/app/main/ui/workspace/nudge.cljs @@ -12,7 +12,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input*]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -32,8 +31,7 @@ {::mf/register modal/components ::mf/register-as :nudge-option} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - profile (mf/deref refs/profile) + (let [profile (mf/deref refs/profile) nudge (or (get-in profile [:props :nudge]) {:big 10 :small 1}) update-big (mf/use-fn #(st/emit! (dw/update-nudge {:big %}))) update-small (mf/use-fn #(st/emit! (dw/update-nudge {:small %}))) @@ -43,45 +41,24 @@ (->> (events/listen js/document EventType.KEYDOWN on-keydown) (partial events/unlistenByKey))) - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container)} - [:div {:class (stl/css :modal-header)} - [:h2 {:class (stl/css :modal-title)} (tr "modals.nudge-title")] - [:button {:class (stl/css :modal-close-btn) - :on-click on-close} i/close-refactor]] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :input-wrapper)} - [:label {:class (stl/css :modal-msg) - :for "nudge-small"} (tr "modals.small-nudge")] - [:> numeric-input* {:min 0.01 - :id "nudge-small" - :value (:small nudge) - :on-change update-small}]] - [:div {:class (stl/css :input-wrapper)} - [:label {:class (stl/css :modal-msg) - :for "nudge-big"} (tr "modals.big-nudge")] - [:> numeric-input* {:min 0.01 - :id "nudge-big" - :value (:big nudge) - :on-change update-big}]]]]] - - - [:div.nudge-modal-overlay - [:div.nudge-modal-container - [:div.nudge-modal-header - [:p.nudge-modal-title (tr "modals.nudge-title")] - [:button.modal-close-button {:on-click on-close} i/close]] - [:div.nudge-modal-body - [:div.input-wrapper - [:span - [:p.nudge-subtitle (tr "modals.small-nudge")] - [:> numeric-input* {:min 0.01 - :value (:small nudge) - :on-change update-small}]]] - [:div.input-wrapper - [:span - [:p.nudge-subtitle (tr "modals.big-nudge")] - [:> numeric-input* {:min 0.01 - :value (:big nudge) - :on-change update-big}]]]]]]))) + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} (tr "modals.nudge-title")] + [:button {:class (stl/css :modal-close-btn) + :on-click on-close} i/close-refactor]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :input-wrapper)} + [:label {:class (stl/css :modal-msg) + :for "nudge-small"} (tr "modals.small-nudge")] + [:> numeric-input* {:min 0.01 + :id "nudge-small" + :value (:small nudge) + :on-change update-small}]] + [:div {:class (stl/css :input-wrapper)} + [:label {:class (stl/css :modal-msg) + :for "nudge-big"} (tr "modals.big-nudge")] + [:> numeric-input* {:min 0.01 + :id "nudge-big" + :value (:big nudge) + :on-change update-big}]]]]])) diff --git a/frontend/src/app/main/ui/workspace/nudge.scss b/frontend/src/app/main/ui/workspace/nudge.scss index ff8f775a28..28d4985791 100644 --- a/frontend/src/app/main/ui/workspace/nudge.scss +++ b/frontend/src/app/main/ui/workspace/nudge.scss @@ -8,33 +8,37 @@ .modal-overlay { @extend .modal-overlay-base; - .modal-container { - @extend .modal-container-base; - min-width: $s-408; - border: $s-1 solid var(--modal-border-color); - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } +} - .modal-content { - @include flexColumn; - gap: $s-24; - @include titleTipography; - margin-bottom: $s-24; - .input-wrapper { - @extend .input-with-label; - label { - text-transform: none; - } - } - } +.modal-container { + @extend .modal-container-base; + min-width: $s-408; + border: $s-1 solid var(--modal-border-color); +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include flexColumn; + gap: $s-24; + @include titleTipography; + margin-bottom: $s-24; +} + +.input-wrapper { + @extend .input-with-label; + label { + text-transform: none; } } diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index 27511a6d44..ddda4cf013 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -12,10 +12,7 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.tab-container :refer [tab-container tab-element]] - [app.main.ui.components.tabs-container :refer [tabs-container tabs-element]] - [app.main.ui.context :as ctx] [app.main.ui.hooks.resize :refer [use-resize-hook]] - [app.main.ui.icons :as i] [app.main.ui.workspace.comments :refer [comments-sidebar]] [app.main.ui.workspace.left-header :refer [left-header]] [app.main.ui.workspace.right-header :refer [right-header]] @@ -26,7 +23,6 @@ [app.main.ui.workspace.sidebar.options :refer [options-toolbox]] [app.main.ui.workspace.sidebar.shortcuts :refer [shortcuts-container]] [app.main.ui.workspace.sidebar.sitemap :refer [sitemap]] - [app.util.dom :as dom] [app.util.i18n :refer [tr]] [app.util.object :as obj] [rumext.v2 :as mf])) @@ -47,7 +43,6 @@ (contains? layout :assets) :assets) shortcuts? (contains? layout :shortcuts) show-debug? (contains? layout :debug-panel) - new-css-system (mf/use-ctx ctx/new-css-system) {on-pointer-down :on-pointer-down on-lost-pointer-capture :on-lost-pointer-capture on-pointer-move :on-pointer-move parent-ref :parent-ref size :size} (use-resize-hook :left-sidebar 275 275 500 :x false :left) @@ -65,25 +60,17 @@ [:aside {:ref parent-ref :id "left-sidebar-aside" :data-size size - :class (stl/css-case new-css-system - :global/settings-bar (not new-css-system) - :global/settings-bar-left (not new-css-system) - :left-settings-bar true + :class (stl/css-case :left-settings-bar true :global/two-row (<= size 300) :global/three-row (and (> size 300) (<= size 400)) :global/four-row (> size 400)) :style #js {"--width" (dm/str size "px")}} - (when new-css-system - [:& left-header {:file file :layout layout :project project :page-id page-id}]) + [:& left-header {:file file :layout layout :project project :page-id page-id}] [:div {:on-pointer-down on-pointer-down :on-lost-pointer-capture on-lost-pointer-capture :on-pointer-move on-pointer-move - :class (if ^boolean new-css-system - (stl/css :resize-area) - (dom/classnames :resize-area true))}] - [:div {:class (if ^boolean new-css-system - (stl/css :settings-bar-inside) - (dom/classnames :settings-bar-inside true))} + :class (stl/css :resize-area)}] + [:div {:class (stl/css :settings-bar-inside)} (cond (true? shortcuts?) [:& shortcuts-container] @@ -92,64 +79,32 @@ [:& debug-panel] :else - (if ^boolean new-css-system - [:div {:class (stl/css :tabs-wrapper)} - [:& tab-container - {:on-change-tab on-tab-change - :selected section - :shortcuts? shortcuts? - :collapsable? true - :handle-collapse handle-collapse - :class (stl/css :tab-spacing)} - [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")} - [:div {:class (stl/css :layers-tab) - :style #js {"--height" (str size-pages "px")}} - [:& sitemap {:layout layout - :toggle-pages toggle-pages - :show-pages? @show-pages? - :size size-pages}] - (when @show-pages? - [:div {:class (stl/css :resize-area-horiz) - :on-pointer-down on-pointer-down-pages - :on-lost-pointer-capture on-lost-pointer-capture-pages - :on-pointer-move on-pointer-move-pages}]) - [:& layers-toolbox {:size-parent size - :size size-pages}]]] + [:div {:class (stl/css :tabs-wrapper)} + [:& tab-container + {:on-change-tab on-tab-change + :selected section + :shortcuts? shortcuts? + :collapsable? true + :handle-collapse handle-collapse + :class (stl/css :tab-spacing)} + [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")} + [:div {:class (stl/css :layers-tab) + :style #js {"--height" (str size-pages "px")}} + [:& sitemap {:layout layout + :toggle-pages toggle-pages + :show-pages? @show-pages? + :size size-pages}] + (when @show-pages? + [:div {:class (stl/css :resize-area-horiz) + :on-pointer-down on-pointer-down-pages + :on-lost-pointer-capture on-lost-pointer-capture-pages + :on-pointer-move on-pointer-move-pages}]) + [:& layers-toolbox {:size-parent size + :size size-pages}]]] - (when-not ^boolean mode-inspect? - [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")} - [:& assets-toolbox]])]] - - [:* - [:button.collapse-sidebar - {:on-click handle-collapse - :aria-label (tr "workspace.sidebar.collapse")} - i/arrow-slide] - - [:& tabs-container - {:on-change-tab on-tab-change - :selected section - :shortcuts? shortcuts? - :collapsable? true - :handle-collapse handle-collapse} - - [:& tabs-element {:id :layers :title (tr "workspace.sidebar.layers")} - [:div {:class :layers-tab - :style #js {"--height" (str size-pages "px")}} - [:& sitemap {:layout layout - :toggle-pages toggle-pages - :show-pages? @show-pages? - :size size-pages}] - (when @show-pages? - [:div.resize-area-horiz - {:on-pointer-down on-pointer-down-pages - :on-lost-pointer-capture on-lost-pointer-capture-pages - :on-pointer-move on-pointer-move-pages}]) - [:& layers-toolbox {:size-parent size}]]] - - (when-not ^boolean mode-inspect? - [:& tabs-element {:id :assets :title (tr "workspace.toolbar.assets")} - [:& assets-toolbox]])]]))]])) + (when-not ^boolean mode-inspect? + [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")} + [:& assets-toolbox]])]])]])) ;; --- Right Sidebar (Component) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs index 4b584aea7a..f9fcbc82a3 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs @@ -64,8 +64,8 @@ (mf/html [:div {:class (stl/css :special-title)} file-name]))} (when-not local? - [:span.tool-link.tooltip.tooltip-left {:alt "Open library file"} - [:a {:class (dom/classnames true) + [:span {:title "Open library file"} + [:a {:class (stl/css :file-link) :href (str "#" url) :target "_blank" :on-click dom/stop-propagation} From af99bf05e2550116bcd4674cb90136c7ad913748 Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 3 Jan 2024 14:17:17 +0100 Subject: [PATCH 24/35] :recycle: Remove new-css-system from dashboard --- .../styles/common/refactor/basic-rules.scss | 2 +- frontend/resources/styles/main-default.scss | 10 - .../styles/main/partials/comments.scss | 467 ---- .../styles/main/partials/dashboard-fonts.scss | 254 --- .../styles/main/partials/dashboard-grid.scss | 527 ----- .../main/partials/dashboard-header.scss | 139 -- .../main/partials/dashboard-settings.scss | 303 --- .../main/partials/dashboard-sidebar.scss | 476 ---- .../styles/main/partials/dashboard-team.scss | 605 ------ .../styles/main/partials/dashboard.scss | 638 ------ .../resources/styles/main/partials/modal.scss | 1930 ----------------- .../styles/main/partials/share-link.scss | 243 --- .../partials/sidebar-document-history.scss | 139 -- frontend/src/app/main/ui/auth/recovery.cljs | 85 +- .../src/app/main/ui/auth/verify_token.cljs | 7 +- .../app/main/ui/components/code_block.cljs | 8 +- .../main/ui/components/context_menu_a11y.cljs | 216 +- .../src/app/main/ui/components/forms.cljs | 8 +- .../app/main/ui/components/tab_container.cljs | 6 +- frontend/src/app/main/ui/dashboard.cljs | 223 +- .../src/app/main/ui/dashboard/comments.cljs | 120 +- .../src/app/main/ui/dashboard/comments.scss | 15 +- frontend/src/app/main/ui/dashboard/files.cljs | 219 +- frontend/src/app/main/ui/dashboard/fonts.cljs | 457 ++-- frontend/src/app/main/ui/dashboard/grid.cljs | 691 ++---- .../app/main/ui/dashboard/inline_edition.cljs | 35 +- .../app/main/ui/dashboard/inline_edition.scss | 58 +- .../src/app/main/ui/dashboard/libraries.cljs | 37 +- .../app/main/ui/dashboard/placeholder.cljs | 68 +- .../src/app/main/ui/dashboard/projects.cljs | 519 ++--- .../src/app/main/ui/dashboard/search.cljs | 82 +- .../src/app/main/ui/dashboard/sidebar.cljs | 876 +++----- frontend/src/app/main/ui/dashboard/team.scss | 91 +- .../src/app/main/ui/dashboard/templates.cljs | 233 +- .../src/app/main/ui/onboarding/questions.cljs | 327 +-- frontend/src/app/main/ui/settings.cljs | 81 +- .../app/main/ui/settings/access_tokens.cljs | 2 +- .../app/main/ui/settings/access_tokens.scss | 157 +- .../src/app/main/ui/settings/feedback.cljs | 127 +- .../src/app/main/ui/settings/options.cljs | 90 +- .../src/app/main/ui/settings/password.cljs | 102 +- .../src/app/main/ui/settings/profile.cljs | 152 +- .../src/app/main/ui/settings/sidebar.cljs | 141 +- frontend/src/app/main/ui/static.cljs | 116 +- .../src/app/main/ui/viewer/share_link.scss | 12 + .../workspace/colorpicker/color_inputs.cljs | 177 +- .../main/ui/workspace/sidebar/history.scss | 2 +- .../main/ui/workspace/viewport/comments.cljs | 73 +- .../viewport/grid_layout_editor.cljs | 33 +- .../ui/workspace/viewport/path_actions.cljs | 214 +- .../ui/workspace/viewport/pixel_overlay.cljs | 16 +- .../app/main/ui/workspace/viewport/rules.cljs | 46 +- 52 files changed, 1917 insertions(+), 9738 deletions(-) delete mode 100644 frontend/resources/styles/main/partials/comments.scss delete mode 100644 frontend/resources/styles/main/partials/dashboard-fonts.scss delete mode 100644 frontend/resources/styles/main/partials/dashboard-grid.scss delete mode 100644 frontend/resources/styles/main/partials/dashboard-header.scss delete mode 100644 frontend/resources/styles/main/partials/dashboard-settings.scss delete mode 100644 frontend/resources/styles/main/partials/dashboard-sidebar.scss delete mode 100644 frontend/resources/styles/main/partials/dashboard-team.scss delete mode 100644 frontend/resources/styles/main/partials/dashboard.scss delete mode 100644 frontend/resources/styles/main/partials/modal.scss delete mode 100644 frontend/resources/styles/main/partials/share-link.scss delete mode 100644 frontend/resources/styles/main/partials/sidebar-document-history.scss diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index 5ca389803e..25d70b6f66 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -216,6 +216,7 @@ .button-disabled { @include buttonStyle; @include flexCenter; + height: $s-32; background-color: var(--button-background-color-disabled); border: $s-1 solid var(--button-border-color-disabled); color: var(--button-foreground-color-disabled); @@ -738,7 +739,6 @@ @include titleTipography; color: var(--color-foreground-primary); text-align: left; - display: grid; grid-template-columns: 1fr 22px; grid-template-areas: "name button"; diff --git a/frontend/resources/styles/main-default.scss b/frontend/resources/styles/main-default.scss index 4ce046332b..8690f68d52 100644 --- a/frontend/resources/styles/main-default.scss +++ b/frontend/resources/styles/main-default.scss @@ -44,7 +44,6 @@ //################################################# @import "common/framework"; -@import "main/partials/modal"; @import "main/partials/forms"; @import "main/partials/texts"; @import "main/partials/context-menu"; @@ -58,13 +57,6 @@ @import "main/partials/viewer-header"; @import "main/partials/viewer-thumbnails"; @import "main/partials/activity-bar"; -@import "main/partials/dashboard"; -@import "main/partials/dashboard-header"; -@import "main/partials/dashboard-grid"; -@import "main/partials/dashboard-sidebar"; -@import "main/partials/dashboard-team"; -@import "main/partials/dashboard-settings"; -@import "main/partials/dashboard-fonts"; @import "main/partials/debug-icons-preview"; @import "main/partials/editable-label"; @import "main/partials/loader"; @@ -74,9 +66,7 @@ @import "main/partials/tool-bar"; @import "main/partials/user-settings"; @import "main/partials/workspace"; -@import "main/partials/comments"; @import "main/partials/color-bullet"; @import "main/partials/inspect"; @import "main/partials/exception-page"; -@import "main/partials/share-link"; @import "main/partials/signup-questions"; diff --git a/frontend/resources/styles/main/partials/comments.scss b/frontend/resources/styles/main/partials/comments.scss deleted file mode 100644 index 7c2d4bf002..0000000000 --- a/frontend/resources/styles/main/partials/comments.scss +++ /dev/null @@ -1,467 +0,0 @@ -.comments-section { - .thread-bubble { - position: absolute; - display: flex; - transform: translate(-15px, -15px); - - cursor: pointer; - pointer-events: auto; - background-color: $color-gray-10; - color: $color-gray-60; - border: 1px solid #b1b2b5; - box-sizing: border-box; - box-shadow: 0px 4px 4px rgba($color-black, 0.25); - - font-size: $fs12; - width: 30px; - height: 30px; - border-radius: 50%; - - display: flex; - align-items: center; - justify-content: center; - - &.resolved { - color: $color-gray-10; - background-color: $color-gray-50; - } - - &.unread { - background-color: $color-primary; - } - span { - user-select: none; - } - } - - .thread-content { - position: absolute; - pointer-events: auto; - margin-left: 10px; - background: $color-white; - border: 1px solid $color-gray-20; - box-sizing: border-box; - box-shadow: 0px 2px 8px rgba($color-black, 0.25); - border-radius: $br2; - min-width: 280px; - max-width: 280px; - user-select: text; - - .comments { - max-height: 420px; - min-height: 105px; - overflow-y: auto; - } - - hr { - border: 0; - height: 1px; - background-color: $color-gray-20; - margin: 0px 10px; - } - } - - .reply-form { - display: flex; - padding: 10px; - flex-direction: column; - - &.edit-form { - padding-bottom: 0px; - } - - textarea { - font-family: "worksans", sans-serif; - font-size: $fs12; - min-height: 32px; - outline: none; - overflow: hidden; - padding: $size-2; - resize: none; - width: 100%; - border-radius: $br2; - border: 1px solid $color-gray-20; - max-height: 4rem; - } - - .buttons { - margin-top: 10px; - display: flex; - justify-content: flex-end; - - input { - margin: 0px; - font-size: $fs14; - - &:not(:last-child) { - margin-right: 6px; - } - } - } - } - - .comment-container { - position: relative; - } - - .comment { - display: flex; - flex-direction: column; - padding: $size-4 $size-2; - - .author { - display: flex; - align-items: center; - height: 26px; - max-height: 26px; - position: relative; - - .name { - display: flex; - flex-direction: column; - - .fullname { - font-weight: $fw700; - color: $color-gray-60; - font-size: $fs12; - - @include text-ellipsis; - width: 174px; - } - .timeago { - margin-top: -2px; - font-size: $fs12; - color: $color-gray-30; - } - } - - .avatar { - display: flex; - align-items: center; - padding-right: 6px; - - img { - border-radius: 50%; - flex-shrink: 0; - height: 24px; - width: 24px; - } - } - - .options-resolve { - position: absolute; - right: 20px; - top: 0px; - width: 16px; - height: 16px; - - cursor: pointer; - - svg { - width: 16px; - height: 16px; - fill: $color-gray-30; - } - } - - .options { - position: absolute; - right: -2px; - top: 2px; - height: 16px; - display: flex; - align-items: center; - cursor: pointer; - - .options-icon { - svg { - width: 14px; - height: 14px; - fill: $color-black; - } - } - } - } - - .content { - margin: $size-4 0; - font-size: $fs14; - color: $color-black; - .text { - margin: 0 $size-2 0 26px; - white-space: pre-wrap; - display: inline-block; - word-break: break-word; - } - } - } - - .comment-options-dropdown { - top: 7px; - right: 7px; - width: 150px; - - border: 1px solid #b1b2b5; - } -} - -.workspace-comment-threads-sidebar-header { - display: flex; - background-color: $color-black; - height: 34px; - align-items: center; - padding: 0px 9px; - color: $color-gray-10; - font-size: $fs12; - justify-content: space-between; - - .options { - display: flex; - margin-right: 3px; - cursor: pointer; - - .label { - padding-right: 8px; - } - - .icon { - display: flex; - align-items: center; - } - - svg { - fill: $color-gray-10; - width: 10px; - height: 10px; - } - } - - .dropdown { - top: 80px; - right: 7px; - } -} - -.comment-threads-section { - pointer-events: auto; - - .thread-groups { - height: calc(100% - 34px); - overflow-y: scroll; - hr { - border: 0; - height: 1px; - background-color: $color-gray-30; - margin: 0px 0px; - } - } - - .thread-group { - display: flex; - flex-direction: column; - font-size: $fs12; - - .section-title { - margin: 0px 10px; - margin-top: 15px; - - .icon { - margin-right: 4px; - } - - .label { - &.filename { - font-weight: $fw700; - } - } - - svg { - fill: $color-gray-10; - height: 10px; - width: 10px; - } - } - } - - .thread-bubble { - position: unset; - transform: unset; - width: 24px; - height: 24px; - margin-right: 6px; - box-shadow: unset; - } - - .comment { - cursor: pointer; - .author { - margin-bottom: $size-4; - .name { - display: flex; - - .fullname { - width: unset; - max-width: 170px; - color: $color-gray-20; - padding-right: 3px; - } - .timeago { - margin-top: unset; - color: $color-gray-20; - } - } - } - - .content { - margin-top: 0px; - color: $color-white; - - &.replies { - margin: 0 $size-2 0 26px; - display: flex; - .total-replies { - margin-right: 9px; - color: $color-info; - } - - .new-replies { - color: $color-primary; - } - } - } - } -} - -.viewer-comments-container { - width: 100%; - height: 100%; - z-index: 1; - position: absolute; - top: 0px; - left: 0px; -} - -.workspace-comments-container { - width: 100%; - height: 100%; - grid-column: 1 / span 2; - grid-row: 1 / span 2; - z-index: 1000; - pointer-events: none; - overflow: hidden; - user-select: text; - - .threads { - position: absolute; - top: 0px; - left: 0px; - } -} - -.dashboard-comments-section { - width: 25px; - height: 25px; - display: flex; - align-items: center; - justify-content: center; - background-color: $color-dashboard; - border-radius: $br3; - position: relative; - - .button { - width: 25px; - height: 25px; - display: flex; - align-items: center; - justify-content: center; - background-color: $color-dashboard; - border-radius: $br3; - - svg { - width: 15px; - height: 15px; - } - - &.unread { - background-color: $color-warning; - } - - &.open { - background-color: $color-black; - svg { - fill: $color-primary; - } - } - } - - .dropdown { - width: 280px; - bottom: 35px; - left: 0px; - border-radius: $br3; - } - - .header { - display: flex; - height: 40px; - align-items: center; - padding: 0px 11px; - - h3 { - font-weight: $fw400; - color: $color-black; - font-size: $fs14; - line-height: $lh-128; // Original value was $fs18 => 1.125rem = 18px; 18px/14px = 128.571428571% => $lh-128 (rounded) - flex-grow: 1; - } - - .close { - display: flex; - align-items: center; - } - - svg { - width: 15px; - height: 15px; - transform: rotate(45deg); - } - } - - .thread-groups { - max-height: calc(30rem - 40px); - overflow: auto; - - hr { - background-color: $color-gray-10; - } - } - - .thread-group .section-title { - color: $color-black; - } - - .comment { - .author .name .fullname { - color: $color-gray-40; - } - .content { - color: $color-black; - } - } -} - -.thread-groups-placeholder { - align-items: center; - display: flex; - flex-direction: column; - font-size: $fs12; - padding: $size-5; - text-align: center; - - svg { - fill: $color-gray-20; - height: 24px; - margin-bottom: $size-5; - width: 24px; - } -} diff --git a/frontend/resources/styles/main/partials/dashboard-fonts.scss b/frontend/resources/styles/main/partials/dashboard-fonts.scss deleted file mode 100644 index 544e50341e..0000000000 --- a/frontend/resources/styles/main/partials/dashboard-fonts.scss +++ /dev/null @@ -1,254 +0,0 @@ -.dashboard-fonts { - display: flex; - flex-direction: column; - align-items: center; - - .dashboard-installed-fonts { - max-width: 1000px; - width: 100%; - display: flex; - margin-top: $size-5; - flex-direction: column; - - h3 { - font-size: $fs14; - color: $color-gray-30; - margin: $size-1; - } - - .font-item { - color: $color-black; - } - } - - .installed-fonts-header { - color: $color-gray-40; - display: flex; - height: 40px; - font-size: $fs12; - background-color: $color-white; - align-items: center; - padding: 0px $size-5; - - > .family { - min-width: 200px; - width: 200px; - } - - > .variants { - padding-left: 12px; - } - - .search-input { - display: flex; - flex-grow: 1; - justify-content: flex-end; - - input { - font-size: $fs12; - border: 1px solid $color-gray-30; - border-radius: $br3; - width: 130px; - padding: $size-1; - margin: 0px; - } - } - } - - .font-item { - color: $color-gray-40; - font-size: $fs14; - background-color: $color-white; - display: flex; - max-width: 1000px; - width: 100%; - min-height: 97px; - align-items: center; - padding: $size-5; - justify-content: space-between; - - &:not(:first-child) { - border-top: 1px solid $color-gray-10; - } - - input { - border: 1px solid $color-gray-30; - border-radius: $br3; - margin: 0px; - padding: $size-2; - font-size: $fs12; - } - - > .family { - min-width: 200px; - width: 200px; - } - - > .filenames { - min-width: 200px; - } - - > .variants { - font-size: $fs14; - display: flex; - flex-wrap: wrap; - flex-grow: 1; - - .variant { - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px 12px; - cursor: pointer; - - .icon { - display: flex; - height: 16px; - width: 16px; - margin-left: 6px; - align-items: center; - svg { - fill: transparent; - width: 12px; - height: 12px; - transform: rotate(45deg); - } - } - - &:hover { - .icon svg { - fill: $color-gray-30; - } - } - } - } - - .filenames { - display: flex; - flex-direction: column; - font-size: $fs12; - } - - .options { - display: flex; - justify-content: flex-end; - min-width: 180px; - - .icon { - width: $size-5; - cursor: pointer; - display: flex; - margin-left: 10px; - justify-content: center; - align-items: center; - &.failure { - margin-right: 10px; - svg { - fill: $color-warning; - } - } - svg { - width: 16px; - height: 16px; - } - - &.close { - svg { - transform: rotate(45deg); - } - } - } - } - } - - .dashboard-fonts-upload { - max-width: 1000px; - width: 100%; - display: flex; - flex-direction: column; - - .upload-button { - width: 100px; - } - - .btn-secondary { - margin-left: 10px; - } - } - - .dashboard-fonts-hero { - font-size: $fs14; - padding: $size-6; - background-color: $color-white; - margin-top: $size-6; - display: flex; - justify-content: space-between; - - .banner { - background-color: $color-info-lighter; - display: grid; - grid-template-columns: 40px 1fr; - &:not(:last-child) { - margin-bottom: 10px; - } - .icon { - display: flex; - align-items: flex-start; - justify-content: center; - padding-top: 10px; - background-color: $color-info; - svg { - fill: $color-white; - } - } - .content { - margin: 10px; - } - &.warning { - background-color: $color-warning-lighter; - .icon { - background-color: $color-warning; - } - } - } - - .desc { - h2 { - margin-bottom: $size-4; - color: $color-black; - } - width: 80%; - color: $color-gray-40; - } - - .btn-primary { - flex-shrink: 0; - } - } - - .fonts-placeholder { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - max-width: 1000px; - width: 100%; - height: 161px; - - border: 1px dashed $color-gray-20; - margin-top: 16px; - - .icon { - svg { - fill: $color-gray-40; - width: 32px; - height: 32px; - } - } - - .label { - color: $color-gray-40; - font-size: $fs14; - } - } -} diff --git a/frontend/resources/styles/main/partials/dashboard-grid.scss b/frontend/resources/styles/main/partials/dashboard-grid.scss deleted file mode 100644 index e5f14c116a..0000000000 --- a/frontend/resources/styles/main/partials/dashboard-grid.scss +++ /dev/null @@ -1,527 +0,0 @@ -// 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 - -.dashboard-grid { - font-size: $fs14; - height: 100%; - overflow: hidden; - overflow-y: auto; - margin-bottom: 0; - - .grid-row { - display: grid; - width: 99%; - margin-left: 13px; - } - - .grid-item { - align-items: center; - cursor: pointer; - display: flex; - flex-direction: column; - flex: 1 0 260px; - height: 230px; - margin: $size-3 $size-4 $size-4 $size-2; - position: relative; - text-align: center; - a, - button { - width: 100%; - font-weight: $fw400; - } - button { - background-color: transparent; - border: none; - } - @media #{$bp-max-1366} { - height: 200px; - flex: 1 0 230px; - } - - &:hover { - .grid-item-th { - border: 2px solid $color-primary; - } - } - - .grid-item-th { - border-radius: $br3; - border: 2px solid lighten($color-gray-20, 15%); - text-align: initial; - - img { - object-fit: contain; - } - } - - &.dragged { - border-radius: $br3; - border: 2px solid lighten($color-gray-20, 15%); - text-align: initial; - max-height: 160px; - } - - &.placeholder { - min-width: 115px; - max-width: 115px; - - display: flex; - flex-direction: column; - justify-content: center; - - .placeholder-icon { - svg { - transform: rotate(-90deg); - width: 20px; - height: 20px; - fill: $color-gray-30; - } - } - - .placeholder-label { - font-size: $fs14; - } - } - - &.overlay { - border-radius: $br4; - border: 2px solid $color-primary; - height: 100%; - opacity: 0; - pointer-events: none; - position: absolute; - width: 100%; - z-index: 1; - } - - &:hover .overlay { - display: block; - opacity: 1; - } - - &.small-item { - max-width: 12%; - min-width: 190px; - padding: $size-4; - justify-content: center; - } - - .grid-item-icon { - width: 90px; - height: 90px; - } - .info-wrapper { - display: grid; - grid-template-columns: 1fr auto; - } - - .item-info { - display: grid; - padding: $size-2; - text-align: left; - width: 100%; - font-size: $fs12; - - h3 { - border: 1px solid transparent; - color: $color-gray-60; - font-size: $fs14; - font-weight: $fw500; - overflow: hidden; - padding: 0; - height: 27px; - padding-right: $size-2; - text-overflow: ellipsis; - width: 100%; - white-space: nowrap; - line-height: $lh-192; // Original value was 27px; 27px/14px = 192.857142857% => $lh-192 (rounded) - max-width: 260px; - @media #{$bp-max-1366} { - max-width: 230px; - } - } - - span.date { - color: $color-gray-30; - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - white-space: nowrap; - max-width: 260px; - &::first-letter { - text-transform: capitalize; - } - @media #{$bp-max-1366} { - max-width: 230px; - } - } - - .edit-wrapper { - .element-title { - padding: 0px; - height: 25px; - color: $color-gray-60; - font-size: $fs14; - font-weight: $fw400; - } - } - } - - .item-badge { - background-color: $color-white; - border: 1px solid $color-gray-20; - border-radius: $br2; - position: absolute; - top: $size-2; - right: $size-2; - height: 32px; - width: 32px; - display: flex; - align-items: center; - justify-content: center; - - svg { - fill: $color-gray-30; - height: 16px; - width: 16px; - } - } - - &.add-file { - border: 1px dashed $color-gray-20; - justify-content: center; - box-shadow: none; - - span { - color: $color-gray-60; - font-size: $fs14; - } - - &:hover { - background-color: $color-white; - border: 2px solid $color-primary; - } - } - - // PROJECTS, ELEMENTS & ICONS GRID - &.project-th { - background-color: $color-white; - - &:hover, - &:focus, - &:focus-within { - .project-th-actions { - opacity: 1; - } - a { - text-decoration: none; - } - } - - .selected { - .grid-item-th { - border: 2px solid $color-primary; - } - } - - .project-th-actions { - align-items: center; - opacity: 0; - display: flex; - right: 5px; - justify-content: center; - width: 30px; - height: 100%; - - span { - color: $color-black; - } - - .project-th-icon { - align-items: center; - display: flex; - margin-right: $size-2; - - &.menu { - margin-right: 0; - display: flex; - justify-content: center; - align-items: flex-end; - flex-direction: column; - width: 100%; - height: 30px; - margin-top: 20px; - - > svg { - fill: $color-gray-60; - margin-right: 0; - height: 18px; - width: 18px; - } - - &:hover, - &:focus { - > svg { - fill: $color-primary-dark; - } - } - } - } - } - - .project-th-actions.force-display { - opacity: 1; - } - } - - // IMAGES SECTION - &.images-th { - border: 1px dashed $color-gray-20; - border-bottom: 2px solid lighten($color-gray-20, 12%); - - &:hover { - border-color: $color-primary; - } - } - - .grid-item-image { - svg { - max-height: 100px; - max-width: 100px; - min-height: 40px; - min-width: 40px; - width: 8vw; - } - } - - .color-swatch { - border-top-left-radius: $br5; - border-top-right-radius: $br5; - height: 25%; - left: 0; - position: absolute; - top: 0; - width: 100%; - } - - .color-data { - color: $color-gray-30; - margin-top: 15px; - } - - .drag-counter { - position: absolute; - top: 5px; - left: 4px; - width: 32px; - height: 32px; - background-color: $color-primary; - border-radius: 50%; - color: $color-black; - font-size: $fs18; - display: flex; - justify-content: center; - align-items: center; - } - } - - .grid-item-th { - background-position: center; - background-size: auto 80%; - background-repeat: no-repeat; - border-top-left-radius: $br3; - border-top-right-radius: $br3; - height: 230px; - max-height: 160px; - overflow: hidden; - position: relative; - width: 100%; - - background-color: $color-canvas; - display: flex; - justify-content: center; - flex-direction: row; - - .img-th { - height: auto; - width: 100%; - } - - svg { - height: 100%; - width: 100%; - } - - svg#loader-pencil { - fill: $color-gray-20; - } - } - - // LIBRARY VIEW - .grid-item { - .library { - height: 580px; - } - - &.project-th.library { - height: 610px; - width: 300px; - } - - .grid-item-th.library { - background-color: $color-gray-50; - flex-direction: column; - height: 90%; - justify-content: flex-start; - max-height: 550px; - padding: $size-6; - - .asset-section { - font-size: $fs12; - color: $color-gray-20; - - &:not(:first-child) { - margin-top: $size-4; - } - } - - .asset-title { - display: flex; - font-size: $fs12; - text-transform: uppercase; - - & .num-assets { - color: $color-gray-30; - } - } - - .asset-list-item { - display: flex; - align-items: center; - border: 1px solid transparent; - border-radius: $br3; - margin-top: $size-1; - padding: 2px; - font-size: $fs12; - color: $color-white; - position: relative; - - & .name-block { - color: $color-gray-20; - width: calc(100% - 24px - #{$size-2}); - } - - & .item-name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - display: block; - } - - & svg { - background-color: $color-canvas; - border-radius: $br4; - border: 2px solid transparent; - height: 24px; - width: 24px; - margin-right: $size-2; - } - - & .color-name { - color: $color-white; - } - - & .color-value { - margin-left: $size-1; - color: $color-gray-30; - text-transform: uppercase; - } - - & .typography-sample { - height: 20px; - margin-right: $size-1; - width: 20px; - } - } - } - } -} - -.grid-empty-placeholder { - border-radius: $br12; - display: grid; - background-color: rgba(227, 227, 227, 0.3); - padding: 13px; - margin-right: 13px; - height: 230px; - &.loader { - justify-items: center; - } - .icon { - display: flex; - align-items: center; - justify-content: center; - } - &.libs { - background-image: url(/images/ph-left.svg), url(/images/ph-right.svg); - background-position: - 15% bottom, - 85% top; - background-repeat: no-repeat; - align-items: center; - border: 1px dashed #b1b2b5; - border-radius: $br3; - display: flex; - flex-direction: column; - height: 200px; - margin: 1rem; - padding: 3rem; - justify-content: center; - .text { - p { - max-width: 360px; - text-align: center; - font-size: $fs16; - } - } - } - .create-new { - background-color: white; - border: 2px solid $color-gray-10; - border-radius: $br3; - color: $color-black; - cursor: pointer; - height: 158px; - font-family: "worksans", sans-serif; - margin: 0.5rem; - &:hover { - border: 2px solid $color-primary; - } - } - - &.search { - align-items: center; - display: flex; - justify-content: center; - flex-direction: column; - height: 200px; - background: $color-white; - border: 1px dashed #e3e3e3; - border-radius: $br0; - } - - svg { - width: 36px; - height: 36px; - fill: $color-gray-20; - } - - .text { - margin-top: 10px; - color: $color-gray-30; - font-size: $fs16; - } -} diff --git a/frontend/resources/styles/main/partials/dashboard-header.scss b/frontend/resources/styles/main/partials/dashboard-header.scss deleted file mode 100644 index 157a440058..0000000000 --- a/frontend/resources/styles/main/partials/dashboard-header.scss +++ /dev/null @@ -1,139 +0,0 @@ -// 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 - -.dashboard-header { - display: flex; - align-items: center; - justify-content: space-between; - background-color: $color-white; - height: 63px; - padding: $size-1 $size-4 $size-1 $size-2; - position: relative; - z-index: 10; - user-select: none; - &.team { - display: grid; - grid-template-columns: 20% 1fr 20%; - } - - .element-name { - margin-right: $size-2; - } - - .btn-secondary { - flex-shrink: 0; - z-index: 10; - height: 32px; - } - - svg { - fill: $color-black; - height: 14px; - margin-right: $size-1; - width: 14px; - } - - nav { - display: flex; - align-items: flex-end; - justify-content: center; - z-index: 1; - - ul { - display: flex; - font-size: $fs14; - justify-content: center; - margin: 0; - } - - li { - a { - display: flex; - align-items: center; - flex-basis: 140px; - border-bottom: 3px solid transparent; - color: $color-gray-30; - height: 40px; - padding: $size-1 $size-5; - font-weight: $fw400; - &:hover { - color: $color-black; - text-decoration: none; - } - } - - &.active { - a { - color: $color-black; - border-color: $color-primary; - } - } - } - } - - .dashboard-title { - display: flex; - align-items: center; - margin-left: 13px; - - h1 { - color: $color-black; - display: flex; - flex-shrink: 0; - font-size: $fs22; - font-weight: $fw600; - z-index: 10; - user-select: all; - } - - .context-menu.is-open { - margin-top: 10px; - } - } - - .icon { - display: flex; - align-items: center; - cursor: pointer; - margin-left: $size-2; - z-index: 10; - - svg { - fill: $color-gray-40; - width: 15px; - height: 15px; - - &:hover { - fill: $color-primary-dark; - } - } - } - - .dashboard-buttons { - display: flex; - justify-content: flex-end; - align-items: center; - } - - .dashboard-header-actions { - display: flex; - } - - .pin-icon { - margin: 0 $size-2 0 $size-5; - background-color: transparent; - border: none; - svg { - fill: $color-gray-20; - } - - &.active { - svg { - fill: $color-gray-50; - } - } - } -} diff --git a/frontend/resources/styles/main/partials/dashboard-settings.scss b/frontend/resources/styles/main/partials/dashboard-settings.scss deleted file mode 100644 index 0cd1146870..0000000000 --- a/frontend/resources/styles/main/partials/dashboard-settings.scss +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) 2020 KALEIDOS INC -// 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 - -.dashboard-sidebar { - &.settings { - .back-to-dashboard { - padding: 12px 18px; - font-size: $fs14; - cursor: pointer; - display: flex; - - .icon { - display: flex; - align-items: center; - margin-right: 14px; - } - - .text { - color: $color-gray-60; - } - - svg { - fill: $color-gray-60; - transform: rotate(90deg); - width: 12px; - height: 12px; - } - } - } -} - -.dashboard-settings { - display: flex; - width: 100%; - justify-content: center; - align-items: center; - - .form-container { - margin-top: 50px; - display: flex; - max-width: 368px; - margin-bottom: 2rem; - width: 100%; - - &.two-columns { - max-width: 536px; - justify-content: space-between; - flex-direction: row; - } - - h2 { - margin-bottom: 1rem; - } - } - - .avatar-form { - display: flex; - flex-direction: column; - width: 120px; - min-width: 120px; - - img { - border-radius: 50%; - flex-shrink: 0; - height: 120px; - margin-right: $size-4; - width: 120px; - } - - .image-change-field { - position: relative; - width: 120px; - height: 120px; - - .update-overlay { - opacity: 0; - cursor: pointer; - position: absolute; - width: 121px; - height: 121px; - border-radius: 50%; - font-size: $fs24; - color: $color-white; - line-height: $lh-500; // Original value was 120px; 120px/24px = 500% => $lh-500 - text-align: center; - background: $color-primary-dark; - z-index: 14; - } - - input[type="file"] { - width: 120px; - height: 120px; - position: absolute; - opacity: 0; - cursor: pointer; - top: 0; - z-index: 15; - } - - &:hover { - .update-overlay { - opacity: 0.8; - } - } - } - } - - .profile-form { - display: flex; - flex-direction: column; - max-width: 368px; - width: 100%; - - .newsletter-subs { - border-bottom: 1px solid $color-gray-20; - border-top: 1px solid $color-gray-20; - padding: 30px 0; - margin-bottom: 31px; - - .newsletter-title { - font-family: "worksans", sans-serif; - color: $color-gray-30; - font-size: $fs14; - } - - label { - font-family: "worksans", sans-serif; - color: $color-gray-60; - font-size: $fs12; - margin-right: -17px; - margin-bottom: 13px; - } - - .info { - font-family: "worksans", sans-serif; - color: $color-gray-30; - font-size: $fs12; - margin-bottom: 8px; - } - - .input-checkbox label { - align-items: flex-start; - } - } - } - - .options-form, - .password-form { - h2 { - font-size: $fs14; - margin-bottom: 20px; - } - } -} - -.dashboard-access-tokens { - display: flex; - flex-direction: column; - align-items: center; - - .access-tokens-hero-container { - max-width: 1000px; - width: 100%; - display: flex; - flex-direction: column; - } - - .access-tokens-hero { - font-size: $fs14; - padding: $size-6; - background-color: $color-white; - margin-top: $size-6; - display: flex; - justify-content: space-between; - - .desc { - width: 80%; - color: $color-gray-40; - h2 { - margin-bottom: $size-4; - color: $color-black; - } - p { - font-size: $fs16; - } - } - - .btn-primary { - flex-shrink: 0; - } - } - - .access-tokens-empty { - text-align: center; - max-width: 1000px; - width: 100%; - padding: $size-6; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - border: 1px dashed $color-gray-20; - color: $color-gray-40; - margin-top: 12px; - min-height: 136px; - } - - .table-row { - background-color: $color-white; - display: grid; - grid-template-columns: 1fr 43% 12px; - height: 63px; - &:not(:first-child) { - margin-top: 8px; - } - } - - .table-field { - &.name { - color: $color-gray-60; - } - - &.expiration-date { - color: $color-gray-40; - font-size: $fs14; - .content { - padding: 2px 5px; - &.expired { - background-color: $color-warning-lighter; - border-radius: $br4; - color: $color-gray-40; - } - } - } - - &.access-token-created { - word-break: break-all; - } - - &.actions { - position: relative; - } - } -} - -.access-tokens-modal { - .action-buttons { - gap: 10px; - - .cancel-button { - border: 1px solid $color-gray-30; - background: $color-canvas; - border-radius: $br3; - padding: 0.5rem 1rem; - cursor: pointer; - margin-right: 8px; - - &:hover { - background: $color-gray-20; - } - } - } - .access-token-created { - position: relative; - word-break: break-all; - - .custom-input input { - background-color: $color-success-lighter; - border: 0; - padding: 0 0 0 15px; - } - } - - .help-icon { - border: none; - height: 40px; - width: 40px; - position: absolute; - top: 0; - right: 0; - cursor: pointer; - background-color: $color-success-lighter; - - svg { - fill: $color-gray-30; - } - - &:hover { - svg { - fill: $color-gray-60; - } - } - } - - .token-created-info { - font-size: $fs12; - color: $color-gray-40; - } -} diff --git a/frontend/resources/styles/main/partials/dashboard-sidebar.scss b/frontend/resources/styles/main/partials/dashboard-sidebar.scss deleted file mode 100644 index 646d53a303..0000000000 --- a/frontend/resources/styles/main/partials/dashboard-sidebar.scss +++ /dev/null @@ -1,476 +0,0 @@ -// 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 - -.dashboard-sidebar { - background-color: $color-white; - z-index: 1; - display: flex; - flex-direction: column; - height: 100%; - padding-top: $size-2; - - .sidebar-content { - display: flex; - flex-direction: column; - height: 100%; - overflow-y: auto; - padding: 0; - - hr { - border-color: $color-gray-10; - margin: 1rem 15px; - } - } - - .sidebar-team-switch { - position: relative; - display: flex; - margin: 5px 15px; - - .teams-dropdown { - left: 0; - top: 50px; - z-index: 12; - max-height: 30rem; - min-width: 234px; - overflow-y: auto; - } - - .options-dropdown { - right: 2px; - top: 50px; - z-index: 12; - max-height: 30rem; - min-width: 162px; - } - - .switch-content { - height: 40px; - display: flex; - width: 100%; - border: 1px solid $color-gray-10; - border-radius: $br5; - align-items: center; - } - - .switch-options { - display: flex; - max-width: 22px; - min-width: 28px; - border-left: 1px solid $color-gray-10; - justify-content: center; - align-items: center; - cursor: pointer; - background-color: transparent; - border: none; - svg { - width: 15px; - height: 13px; - fill: $color-gray-60; - } - } - - .current-team { - cursor: pointer; - display: flex; - align-items: center; - flex-grow: 1; - font-size: $fs14; - padding: 0px 10px; - background-color: transparent; - border: none; - } - - .team-name { - flex-grow: 1; - display: flex; - height: 40px; - align-items: center; - - &.action { - .team-icon { - border-radius: 50%; - background-color: $color-gray-10; - height: 24px; - margin-right: 10px; - padding: 6px; - width: 24px; - - svg { - height: 12px; - width: 12px; - } - } - - &:hover { - .team-icon { - background-color: $color-primary; - } - } - - .team-text { - width: 150px; - } - } - - .team-icon { - display: flex; - align-items: center; - padding-right: 10px; - - svg { - width: 23px; - height: 23px; - fill: $color-gray-60; - } - - img { - border-radius: 50%; - flex-shrink: 0; - height: 23px; - width: 23px; - } - } - - .team-text { - color: $color-gray-60; - @include text-ellipsis; - width: 130px; - text-align: left; - } - - .icon { - margin-left: auto; - svg { - fill: $color-gray-60; - } - } - } - - .switch-icon { - display: flex; - align-items: center; - justify-content: center; - svg { - width: 10px; - height: 10px; - fill: $color-gray-60; - } - } - } - - .sidebar-empty-placeholder { - padding: 10px 12px; - color: $color-gray-30; - display: flex; - align-items: flex-start; - - .icon { - padding: 0px 10px; - svg { - fill: $color-gray-30; - width: 12px; - height: 12px; - } - } - .text { - font-size: $fs12; - } - } - - .sidebar-nav { - display: flex; - flex-direction: column; - overflow-y: auto; - margin: 0; - user-select: none; - - // TODO: should be deprecated / unclear name - &.dashboard-common { - overflow: unset; - } - - &.no-overflow { - overflow: unset; - } - - & > li { - align-items: center; - cursor: pointer; - display: flex; - flex-shrink: 0; - padding: $size-2; - a { - font-weight: $fw400; - width: 100%; - &:hover { - text-decoration: none; - } - } - - svg { - fill: $color-black; - margin-right: 8px; - height: $size-3; - width: $size-3; - } - - span.element-title { - color: $color-gray-60; - font-size: $fs14; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - &::before { - background-color: transparent; - border-radius: $br3; - content: ""; - height: 26px; - margin-right: $size-2; - width: 4px; - } - - &.recent-projects { - svg { - fill: $color-white; - } - } - - & .edit-wrapper { - border: 1px solid $color-gray-10; - border-radius: $br3; - display: flex; - width: 100%; - } - - input.element-title { - border: 0; - height: 30px; - padding: 5px; - margin: 0; - width: 100%; - background-color: $color-white; - } - - .close { - background-color: $color-white; - cursor: pointer; - padding-left: 5px; - - svg { - fill: $color-gray-30; - height: 15px; - transform: rotate(45deg) translateY(7px); - width: 15px; - margin: 0; - } - } - - .element-subtitle { - color: $color-gray-20; - font-style: italic; - } - - &:hover { - &::before { - background-color: $color-gray-10; - } - } - - &.current { - a { - font-weight: $fw700; - } - - &::before { - background-color: $color-primary; - } - } - - &.dragging { - background-color: color.adjust($color-primary, $alpha: -0.69); - } - } - } - - .sidebar-search { - align-items: center; - background-color: $color-white; - border: 1px solid $color-gray-10; - border-radius: $br5; - display: flex; - margin: 5px 15px; - - .input-text { - background: transparent; - border: 0; - color: $color-gray-60; - font-size: $fs14; - padding: 6px; - margin: 0; - max-width: 195px; - width: 100%; - height: 40px; - } - - &:focus, - &:focus-within { - border-color: $color-black; - } - - .search, - .clear-search { - align-items: center; - cursor: pointer; - display: flex; - height: 22px; - margin-left: auto; - padding: 0 $size-2; - width: 32px; - - svg { - fill: $color-gray-30; - height: 15px; - width: 15px; - } - } - - .clear-search svg { - transform: rotate(45deg); - - &:hover { - fill: $color-danger; - } - } - } - - &.profile-bar { - background-color: $color-gray-10; - - .dashboard-sidebar-inside { - display: none; - } - } -} - -.projects-row { - align-items: center; - display: flex; - margin-top: 1rem; - padding: $size-2; - position: relative; - - span { - color: $color-gray-30; - font-size: $fs14; - } - - .btn-icon-light { - margin-left: auto; - } - - &::before { - background-color: $color-gray-10; - content: ""; - height: 1px; - left: 4%; - position: absolute; - right: 4%; - top: -5px; - width: 92%; - } -} - -.team-form-modal { - h2 { - font-weight: $fw400; - color: $color-gray-40; - font-size: 28px; - margin-bottom: 30px; - } - - .buttons-row { - margin-top: 20px; - display: flex; - justify-content: center; - } - - input[type="submit"] { - margin-bottom: 0px; - } -} - -.profile-section { - align-items: center; - cursor: pointer; - display: flex; - padding: 10px 15px; - position: relative; - - .profile { - align-items: center; - cursor: pointer; - display: flex; - flex-grow: 1; - - span { - @include text-ellipsis; - color: $color-black; - margin: 10px; - font-size: $fs14; - max-width: 160px; - } - - img { - border-radius: 50%; - flex-shrink: 0; - height: 25px; - width: 25px; - } - svg { - height: 10px; - margin-left: auto; - margin-right: $size-2; - width: 10px; - } - } - - .dropdown { - left: 15px; - bottom: 45px; - min-width: 189px; - - @include animation(0, 0.2s, fadeInUp); - - li { - font-size: $fs14; - padding: $size-2 $size-4; - - svg { - fill: $color-gray-20; - margin-right: $size-2; - - height: 12px; - width: 12px; - } - - &.separator { - border-top: 1px solid $color-gray-10; - } - } - } -} - -.primary-badge { - border: 1px solid $color-primary; - border-radius: $br2; - font-size: $fs9 !important; - font-weight: $fw500; - color: $color-primary !important; - padding: 2px 4px; -} diff --git a/frontend/resources/styles/main/partials/dashboard-team.scss b/frontend/resources/styles/main/partials/dashboard-team.scss deleted file mode 100644 index 5bdfcebda5..0000000000 --- a/frontend/resources/styles/main/partials/dashboard-team.scss +++ /dev/null @@ -1,605 +0,0 @@ -.dashboard-invite-modal { - top: 72px; - right: 13px; - padding: 32px; - box-shadow: 0px 4px 8px rgba($color-black, 0.25); - border-radius: $br8; - width: 400px; - position: fixed; - z-index: 16; - &.hero { - top: 218px; - right: 35px; - } - - form { - width: 100%; - } - - .form-row { - display: flex; - justify-content: space-between; - margin: 4px 0px; - .label { - margin-bottom: 0; - display: flex; - align-items: center; - } - } - - .custom-input { - width: 100%; - min-height: 116px; - max-height: 176px; - overflow-y: hidden; - input { - &.no-padding { - padding-top: 12px; - height: 50px; - } - min-height: 40px; - } - .selected-items { - gap: 8px; - padding: 8px; - max-height: 132px; - overflow-y: scroll; - .selected-item { - .around { - height: 24px; - display: flex; - align-items: center; - justify-content: flex-start; - width: fit-content; - .icon { - display: flex; - align-items: center; - justify-content: center; - } - } - } - } - } - - .custom-select { - width: 180px; - overflow: hidden; - justify-content: normal; - select { - height: auto; - } - } - - .action-buttons { - display: flex; - margin-top: 16px; - input[type="submit"] { - margin-bottom: 0px; - } - } - - .title { - color: $color-black; - font-weight: $fw700; - margin-bottom: 16px; - } - - .hint { - font-size: $fs12; - - &.hidden { - display: none; - } - } - - svg { - width: 12px; - height: 12px; - fill: $color-gray-20; - } - - .error, - .warning { - width: 100%; - display: flex; - .icon { - text-align: center; - padding: 5px; - svg { - fill: $color-white; - width: 20px; - height: 20px; - margin: 5px; - } - } - .text { - color: $color-black; - padding: 5px; - font-size: $fs12; - } - } - - .error { - background-color: #ffd9e0; - - .icon { - background-color: $color-danger; - } - } - - .warning { - background-color: #ffeaca; - - .icon { - background-color: $color-warning; - } - } -} - -.dashboard-team-members, -.dashboard-team-invitations, -.dashboard-team-webhooks { - .empty-invitations { - height: 156px; - max-width: 1040px; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - border: 1px dashed $color-gray-20; - margin-top: 16px; - } - .table-header { - user-select: none; - } - - .table-row { - background-color: $color-white; - height: 63px; - &:not(:first-child) { - margin-top: 16px; - } - } - - .table-field { - &.name { - width: 43%; - min-width: 300px; - display: flex; - .member-info { - display: flex; - flex-direction: column; - margin-left: 16px; - .member-name { - font-size: $fs16; - .you { - color: $color-gray-30; - margin-left: 5px; - } - } - .member-email { - color: $color-gray-30; - font-size: $fs12; - } - } - - .member-image { - height: 32px; - width: 32px; - img { - border-radius: 50%; - } - } - } - - &.roles { - flex-grow: 1; - cursor: default; - position: relative; - .rol-label { - user-select: none; - } - .rol-selector { - &.has-priv { - border: 1px solid $color-gray-20; - cursor: pointer; - } - min-width: 160px; - height: 32px; - display: flex; - justify-content: space-between; - align-items: center; - border-radius: $br2; - padding: 3px 8px; - font-size: $fs14; - } - } - - &.actions { - position: relative; - .actions-dropdown { - max-height: 30rem; - min-width: 180px; - } - } - - &.status { - .status-badge { - color: $color-white; - border-radius: $br12; - min-width: 74px; - height: 24px; - display: flex; - justify-content: center; - align-items: center; - - &.pending { - background-color: $color-warning; - } - - &.expired { - background-color: $color-gray-20; - } - - .status-label { - font-size: $fs12; - } - } - } - - &.uri { - flex-grow: 1; - } - - &.active { - min-width: 100px; - } - - &.last-delivery { - display: flex; - justify-content: center; - width: 50px; - position: relative; - .success svg { - fill: $color-primary; - width: 16px; - height: 16px; - } - .failure svg { - fill: $color-warning; - width: 16px; - height: 16px; - } - - .icon-container { - width: 16px; - height: 16px; - overflow-x: visible; - } - - .icon { - padding: 0; - } - } - - .tooltip { - display: none; - position: absolute; - top: -58px; - left: 50%; - transform: translate(-50%, 0); - text-align: center; - - .label { - border-radius: $br3; - color: $color-white; - background-color: $color-black; - white-space: nowrap; - padding: 12px 20px; - } - - .arrow-down { - margin: 0 auto; - width: 0; - height: 0; - border-left: 8px solid transparent; - border-right: 8px solid transparent; - border-top: 8px solid $color-black; - } - } - - .last-delivery-icon:hover { - .tooltip { - display: block; - } - } - } - - .dropdown { - position: absolute; - max-height: 30rem; - overflow-y: auto; - background-color: $color-white; - border-radius: $br4; - box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25); - z-index: 12; - top: 30px; - left: -151px; - width: 155px; - - hr { - margin: 0; - border-color: $color-gray-10; - } - - li { - display: flex; - align-items: center; - color: $color-gray-60; - cursor: pointer; - font-size: $fs14; - height: 31px; - padding: 5px 16px; - - &.title { - font-weight: $fw600; - cursor: default; - } - - &:hover { - background-color: $color-primary-lighter; - } - } - } -} - -.dashboard-team-settings { - .team-settings { - display: flex; - justify-content: center; - margin-top: 16px; - - svg { - width: 20px; - height: 20px; - } - - .horizontal-blocks { - display: flex; - max-width: 1010px; - justify-content: space-between; - width: 100%; - } - - .block { - display: flex; - max-width: 324px; - width: 324px; - background-color: $color-white; - flex-direction: column; - padding: 12px; - - .label { - font-size: $fs13; - color: $color-gray-30; - } - } - - .info-block { - position: relative; - - .name { - margin-top: 10px; - font-size: $fs24; - color: $color-black; - @include text-ellipsis; - margin-right: 90px; - } - - .icon { - position: absolute; - padding: 15px; - width: 100px; - height: 100px; - right: 0px; - top: 0px; - - img { - border-radius: 50%; - width: 70px; - height: 70px; - } - - .update-overlay { - opacity: 0; - cursor: pointer; - position: absolute; - display: flex; - justify-content: center; - align-items: center; - width: 71px; - height: 71px; - border-radius: 50%; - color: $color-white; - background: $color-primary-dark; - z-index: 14; - - svg { - fill: $color-white; - } - } - - &:hover { - .update-overlay { - opacity: 1; - width: 72px; - height: 72px; - top: 14px; - left: 14px; - } - } - } - } - - .owner-block { - img { - width: 30px; - height: 30px; - border-radius: 50%; - } - - svg { - width: 12px; - height: 12px; - fill: $color-black; - } - - .owner { - margin-top: 5px; - display: flex; - align-items: center; - color: $color-black; - .icon { - margin-right: 12px; - } - } - - .summary { - margin-top: 5px; - color: $color-black; - .icon { - padding: 0px 10px; - margin-right: 12px; - } - } - } - - .stats-block { - svg { - fill: $color-black; - } - - .projects, - .files { - margin-top: 7px; - display: flex; - align-items: center; - color: $color-black; - - .icon { - display: flex; - align-items: center; - padding: 0px 2px; - margin-right: 14px; - } - } - } - } -} - -.dashboard-team-webhooks { - display: flex; - flex-direction: column; - align-items: center; - - .webhooks-hero-container { - max-width: 1000px; - width: 100%; - display: flex; - flex-direction: column; - - .upload-button { - width: 100px; - } - - .btn-secondary { - margin-left: 10px; - } - } - - .webhooks-hero { - font-size: $fs14; - - padding: $size-6; - background-color: $color-white; - margin-top: $size-6; - display: flex; - justify-content: space-between; - - .banner { - background-color: unset; - - display: flex; - - .icon { - display: flex; - align-items: center; - padding-left: 0px; - padding-right: 10px; - svg { - fill: $color-info; - } - } - } - - .desc { - h2 { - margin-bottom: $size-4; - color: $color-black; - } - width: 80%; - color: $color-gray-40; - p { - font-size: $fs16; - } - } - - .btn-primary { - flex-shrink: 0; - } - } - - .webhooks-empty { - text-align: center; - max-width: 1000px; - width: 100%; - padding: $size-6; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - border: 1px dashed $color-gray-20; - color: $color-gray-40; - margin-top: 12px; - min-height: 136px; - } -} - -.webhooks-modal { - .action-buttons { - gap: 10px; - - .cancel-button { - border: 1px solid $color-gray-30; - background: $color-canvas; - border-radius: $br3; - padding: 0.5rem 1rem; - cursor: pointer; - margin-right: 8px; - - &:hover { - background: $color-gray-20; - } - } - } - .input-checkbox label { - font-size: $fs14; - color: $color-black; - } - - .explain { - font-size: $fs12; - color: $color-gray-40; - } -} diff --git a/frontend/resources/styles/main/partials/dashboard.scss b/frontend/resources/styles/main/partials/dashboard.scss deleted file mode 100644 index f48e89e57d..0000000000 --- a/frontend/resources/styles/main/partials/dashboard.scss +++ /dev/null @@ -1,638 +0,0 @@ -// 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 - -.team-hero { - display: flex; - position: relative; - border: 2px solid $color-gray-10; - border-radius: $br8; - padding: 20px; - margin: 0 1rem 0 21px; - height: 154px; - - .text { - flex-grow: 1; - padding-left: 20px; - .title { - font-size: $fs24; - font-weight: $fw700; - color: $color-black; - } - .info { - span { - color: $color-gray-30; - display: block; - } - padding-top: 10px; - } - } - .close { - position: absolute; - top: 20px; - right: 20px; - background-color: transparent; - border: none; - cursor: pointer; - svg { - transform: rotate(45deg); - width: 16px; - height: 16px; - } - } - .invite { - align-self: flex-end; - height: 40px; - font-family: "worksans", sans-serif; - width: 180px; - } - img { - width: 274px; - margin-bottom: -19px; - @media (max-width: 1200px) { - display: none; - width: 0; - } - } -} - -.hero-projects { - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 30px; - margin: 0 1rem 1rem 1.2rem; - .tutorial, - .walkthrough { - display: grid; - grid-template-columns: 1fr 1fr; - position: relative; - border: 2px solid $color-gray-10; - border-radius: $br8; - min-height: 211px; - - .thumbnail { - border-top-left-radius: $br6; - border-bottom-left-radius: $br6; - padding: 30px; - display: block; - background-color: #e0e4e9; - } - - .text { - padding: 30px; - .title { - color: $color-black; - font-size: $fs24; - font-weight: $fw700; - margin-bottom: 8px; - } - .info { - color: $color-gray-50; - margin-bottom: 20px; - font-size: $fs14; - } - } - .action { - font-family: "worksans", sans-serif; - width: 180px; - height: 40px; - } - .close { - position: absolute; - top: 0; - right: 0; - width: $size-5; - cursor: pointer; - display: flex; - margin: 20px; - justify-content: center; - align-items: center; - background-color: transparent; - border: none; - .icon { - svg { - fill: $color-gray-30; - height: 16px; - width: 16px; - transform: rotate(45deg); - &:hover { - fill: $color-primary; - } - } - } - } - - @media (max-width: 1846px) { - grid-template-columns: 190px 1fr; - } - @media (max-width: 1526px) { - grid-template-columns: 1fr; - .img { - display: none; - width: 0; - } - } - } - .walkthrough { - .thumbnail { - background-image: url("/images/walkthrough-cover.png"); - background-position: center; - background-repeat: no-repeat; - background-size: cover; - } - } - .tutorial { - .thumbnail { - background-image: url("/images/hands-on-tutorial.png"); - background-position: center; - background-repeat: no-repeat; - background-size: cover; - } - .loader { - display: flex; - svg#loader-pencil { - width: 31px; - } - } - } -} - -.dashboard-container { - background-color: $color-dashboard; - flex: 1 0 0; - margin-right: $size-4; - overflow-y: auto; - width: 100%; - &.dashboard-projects { - user-select: none; - } - &.no-bg { - background-color: transparent; - } - &.dashboard-shared { - width: calc(100vw - 320px); - margin-right: 50px; - } - - &.search { - margin-top: 10px; - } -} - -.dashboard-project-row { - margin-bottom: $size-5; - position: relative; - - .project { - align-items: center; - background: $color-white; - border-radius: $br3; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-top: $size-4; - padding: $size-2 $size-2 $size-2 $size-4; - width: 99%; - max-height: 40px; - gap: $size-2; - .project-name-wrapper { - display: flex; - align-items: center; - justify-content: flex-start; - min-height: 32px; - margin-left: $size-2; - } - .show-more { - align-items: center; - color: $color-gray-30; - display: flex; - font-size: $fs14; - justify-content: space-between; - cursor: pointer; - background-color: transparent; - border: none; - .placeholder-icon { - transform: rotate(-90deg); - margin-left: 10px; - svg { - height: 14px; - width: 14px; - fill: $color-gray-30; - } - } - &:hover { - color: $color-primary-dark; - svg { - fill: $color-primary-dark; - } - } - } - - .btn-secondary { - border: none; - padding: $size-2; - } - - h2 { - cursor: pointer; - font-size: $fs18; - line-height: $lh-088; // Original value was 1rem = 16px; 16px/18px = 88.88888% => $lh-088 - font-weight: $fw600; - color: $color-black; - margin-right: $size-1; - } - - .edit-wrapper { - margin-right: $size-4; - } - - .info { - font-size: $fs14; - line-height: $lh-115; // Original value was 1rem = 16px; 16px/14px = 114.285714286% => $lh-115 (rounded) - font-weight: $fw400; - color: $color-gray-60; - margin-left: 0.75rem; - @media (max-width: 760px) { - display: none; - } - } - - .project-actions { - display: flex; - opacity: 0; - margin-left: $size-6; - - .btn-small { - height: 32px; - margin: 0 $size-2; - width: 32px; - } - } - - .pin-icon { - cursor: pointer; - display: flex; - align-items: center; - margin-right: 14px; - background-color: transparent; - border: none; - svg { - width: 15px; - height: 15px; - fill: $color-gray-20; - } - - &.active { - svg { - fill: $color-gray-50; - } - } - } - } - - &:hover, - &:focus, - &:focus-within { - .project-actions { - opacity: 1; - } - } - - .show-more { - align-items: center; - color: $color-gray-30; - display: flex; - font-size: $fs14; - justify-content: space-between; - cursor: pointer; - background-color: transparent; - border: none; - position: absolute; - top: 9px; - right: 53px; - .placeholder-icon { - transform: rotate(-90deg); - margin-left: 10px; - svg { - height: 14px; - width: 14px; - fill: $color-gray-30; - } - } - &:hover { - color: $color-primary-dark; - svg { - fill: $color-primary-dark; - } - } - } -} - -.recent-files-row-title-info { - color: $color-gray-60; - line-height: $lh-115; // Original value was 1rem = 16px; 16px/14px = 114.285714286% => $lh-115 - font-size: $fs14; - font-weight: $fw400; - @media (max-width: 880px) { - display: none; - } -} - -.dashboard-table { - display: flex; - flex-direction: column; - align-items: center; - margin-top: 20px; - font-size: $fs16; - - &.team-members { - margin-bottom: 52px; - } - - &.invitations { - .table-row { - display: grid; - grid-template-columns: 43% 1fr 109px 12px; - } - } - - .table-header { - display: grid; - grid-template-columns: 43% 1fr 109px 12px; - max-width: 1040px; - background-color: $color-white; - color: $color-gray-30; - width: 100%; - height: 40px; - padding: 0px 16px; - } - - .table-rows { - display: flex; - flex-direction: column; - max-width: 1040px; - width: 100%; - margin-top: 16px; - color: $color-black; - } - - .table-row { - display: flex; - width: 100%; - height: 45px; - align-items: center; - padding: 0px 16px; - } - - .table-field { - display: flex; - align-items: center; - - .icon { - padding-left: 10px; - cursor: pointer; - } - } - - svg { - width: 10px; - height: 10px; - fill: $color-black; - } -} - -.edit-wrapper { - border: 1px solid $color-gray-10; - border-radius: $br3; - display: flex; - padding-right: $size-5; - position: relative; - - input.element-title { - border: 0; - height: 30px; - padding: 5px; - margin: 0; - width: 100%; - background-color: $color-white; - } - - .close { - cursor: pointer; - position: absolute; - - top: 1px; - right: 2px; - - svg { - fill: $color-gray-30; - height: 15px; - transform: rotate(45deg) translateY(7px); - width: 15px; - margin: 0; - } - } -} - -.import-file-btn { - align-items: center; - display: flex; - flex-direction: column; - height: 2rem; - justify-content: center; - overflow: hidden; - padding: 4px; - width: 2rem; - - background: none; - border: 1px solid $color-gray-20; - border-radius: $br2; - cursor: pointer; - transition: all 0.4s; - margin-left: 1rem; - - &:hover { - background: $color-primary; - } - - svg { - width: 16px; - height: 16px; - } -} - -.dashboard-templates-section { - position: absolute; - display: flex; - flex-direction: column; - justify-content: flex-end; - bottom: 0; - width: 100%; - height: 228px; - transition: bottom 300ms; - pointer-events: none; - &.collapsed { - bottom: -228px; - transition: bottom 300ms; - } - - .title { - pointer-events: all; - width: fit-content; - top: -56px; - right: -28px; - text-align: right; - height: 56px; - position: absolute; - button { - border: none; - cursor: pointer; - height: 58px; - display: inline-flex; - align-items: center; - border-top: 2px solid #e4e4e4; - border-left: 2px solid #e4e4e4; - border-right: 2px solid #e4e4e4; - border-top-left-radius: $br10; - border-top-right-radius: $br10; - margin-right: 30px; - background-color: $color-white; - position: relative; - z-index: 1; - span { - display: inline-block; - vertical-align: middle; - line-height: $lh-normal; - font-size: $fs18; - font-weight: $fw600; - color: $color-black; - margin-left: 18px; - margin-right: 10px; - &.icon { - margin-left: 10px; - margin-right: 16px; - } - } - svg { - width: 12px; - height: 12px; - } - } - } - - .button { - position: absolute; - top: 133px; - border: 2px solid #e0e4e9; - border-radius: 50%; - text-align: center; - width: 35px; - height: 35px; - cursor: pointer; - background-color: $color-white; - display: flex; - align-items: center; - justify-content: center; - pointer-events: all; - svg { - width: 12px; - height: 12px; - } - - &.left { - left: 0; - margin-left: 43px; - } - - &.right { - right: 0; - margin-right: 43px; - } - - &:hover { - border: 2px solid $color-primary; - } - } - - .content { - pointer-events: all; - background-color: $color-white; - width: 200%; - height: 229px; - border-top: 2px solid #e4e4e4; - border-left: 2px solid #e4e4e4; - margin-left: 5px; - position: absolute; - - .card-container { - width: 275px; - margin-top: 20px; - display: inline-block; - text-align: center; - vertical-align: top; - background-color: transparent; - border: none; - padding: 0; - } - - .template-card { - display: inline-block; - width: 255px; - font-size: $fs16; - color: #181a22; - cursor: pointer; - .img-container { - width: 100%; - height: 135px; - margin-bottom: 15px; - border-radius: $br5; - border: 2px solid #e0e4e9; - display: flex; - justify-content: center; - flex-direction: column; - } - - .card-name { - padding: 0 5px; - display: flex; - justify-content: space-between; - height: 23px; - svg { - width: 16px; - height: 16px; - } - span { - font-weight: $fw500; - font-size: $fs14; - } - } - - .template-link { - border: 2px solid transparent; - margin: 30px; - padding: 32px 0; - } - - .template-link-title { - font-size: $fs14; - font-weight: $fw600; - color: $color-gray-60; - } - - .template-link-text { - font-size: $fs12; - margin-top: $size-2; - color: $color-gray-50; - } - - &:hover { - .img-container { - border: 2px solid $color-primary; - } - } - } - } -} diff --git a/frontend/resources/styles/main/partials/modal.scss b/frontend/resources/styles/main/partials/modal.scss deleted file mode 100644 index f3ca1df159..0000000000 --- a/frontend/resources/styles/main/partials/modal.scss +++ /dev/null @@ -1,1930 +0,0 @@ -.modal-overlay { - align-items: center; - background-color: $color-dark-bg; - display: flex; - justify-content: center; - position: fixed; - height: 100%; - left: 0; - top: 0; - width: 100%; - z-index: 1000; - - &.transparent { - background-color: rgba($color-white, 0); - } -} - -.modal, -.generic-modal { - background-color: $color-white; - width: 565px; - display: flex; - position: relative; - - .close { - cursor: pointer; - position: absolute; - right: 16px; - top: 16px; - svg { - width: 16px; - height: 16px; - transform: rotate(45deg); - } - } - - .modal-content { - display: flex; - flex-grow: 1; - flex-direction: column; - padding: 60px 100px; - } - - .button-row { - display: flex; - justify-content: space-between; - - > button { - font-size: $fs12; - } - > button:not(:first-child) { - margin-left: 25px; - } - } -} - -// NEW GEN MODALS - -.modal-container { - border-radius: $br5; - display: flex; - flex-direction: column; - width: 448px; - background-color: $color-white; - max-height: 700px; - - .modal-header { - align-items: center; - background-color: $color-white; - border-radius: $br8 $br8 0 0; - color: $color-black; - display: flex; - height: 63px; - justify-content: space-between; - } - - .modal-header-title { - display: flex; - align-items: center; - font-size: $fs18; - padding-left: 16px; - - h2 { - font-size: $fs18; - font-weight: $fw400; - margin: 0; - } - } - - .modal-close-button { - align-items: center; - cursor: pointer; - display: flex; - height: 30px; - justify-content: center; - margin-right: 16px; - - svg { - transform: rotate(45deg); - width: 16px; - height: 16px; - } - } - - .component-list { - max-height: 408px; - overflow-y: scroll; - } - - .modal-item-element { - display: flex; - padding-bottom: 3px; - margin-left: 10px; - font-size: $fs14; - color: $color-info; - - .modal-component-icon { - margin-right: 16px; - display: flex; - justify-content: center; - align-items: center; - svg { - width: 16px; - height: 16px; - fill: $color-info; - } - } - } - - .modal-content { - display: flex; - flex-direction: column; - padding: 32px; - border-top: 1px solid $color-gray-10; - h3 { - color: $color-gray-40; - font-size: $fs16; - font-weight: $fw400; - } - &.delete-shared { - padding: 15px 32px; - .modal-item-element { - font-size: $fs16; - } - } - } - - .modal-footer { - display: flex; - height: 63px; - padding: 0px 18px; - border-top: 1px solid $color-gray-10; - - .action-buttons { - display: flex; - width: 100%; - height: 100%; - justify-content: flex-end; - // border: 1px solid red; - align-items: center; - - input { - margin-bottom: 0px; - } - } - } - - .btn-disabled { - opacity: 0.5; - } -} - -.change-email-modal { - h2 { - font-size: $fs18; - } - - h3 { - margin-bottom: 15px; - } - - .modal-footer .action-buttons { - justify-content: space-around; - gap: 15px; - } - - .fields-container { - margin-top: 1rem; - } -} - -.confirm-dialog, -.alert-dialog { - background-color: $color-white; - - p { - font-size: $fs14; - color: $color-gray-40; - } - - .action-buttons { - display: flex; - flex-direction: row; - width: 100%; - font-size: $fs14; - } - - .cancel-button { - border: 1px solid $color-gray-30; - background: $color-canvas; - border-radius: $br3; - padding: 0.5rem 1rem; - cursor: pointer; - margin-right: 8px; - - &:hover { - background: $color-gray-20; - } - } - - .accept-button { - border-radius: $br3; - cursor: pointer; - padding: 0.5rem 1rem; - - &.danger { - background: $color-danger; - border: 1px solid $color-danger; - color: $color-white; - &:hover { - background: $color-danger-dark; - } - } - - &.primary { - background: $color-primary; - border: 1px solid $color-primary; - color: $color-black; - - &:hover { - background: $color-primary-dark; - } - } - } -} - -.import-dialog, -.export-dialog, -.export-multiple-dialog { - background-color: $color-white; - border: 1px solid $color-gray-20; - width: 30rem; - min-height: 14rem; - - &.empty { - width: 39rem; - } - - p { - font-size: $fs14; - color: $color-black; - } - - .detail { - font-size: $fs12; - } - - .detail, - .explain { - padding: 0 1rem; - } - - .cancel-button { - border: 1px solid $color-gray-20; - background: $color-white; - border-radius: $br3; - padding: 0.5rem 2.25rem; - cursor: pointer; - margin-right: 18px; - - &:hover { - background: $color-gray-20; - } - } - - .accept-button { - background: $color-primary; - border-radius: $br3; - border: 1px solid $color-primary; - color: $color-black; - cursor: pointer; - padding: 0.5rem 2.25rem; - - &[disabled] { - border: 1px solid #e3e3e3; - } - - &:hover { - background: $color-primary-dark; - } - } - - .modal-content { - flex: 1; - overflow-y: auto; - max-height: calc(65vh); - } - - .modal-header-title { - padding-left: 2rem; - - h2 { - font-size: $fs18; - } - } - - .modal-content { - padding: 1rem; - } - - .file-entry { - margin: 0.75rem 1rem; - user-select: none; - - &.editable:hover { - .file-name-label { - background-color: $color-primary-lighter; - } - .edit-entry-buttons { - display: flex; - background-color: $color-primary-lighter; - } - } - } - - .file-icon { - width: 18px; - display: flex; - align-items: center; - justify-content: center; - margin-right: 1rem; - - svg { - width: 18px; - height: 18px; - } - - #loader-pencil { - fill: $color-black; - } - - .icon-tick { - fill: $color-success; - } - - .icon-msg-warning { - fill: $color-warning; - } - - .icon-close { - transform: rotate(45deg); - fill: $color-danger; - } - } - - .file-name { - display: flex; - align-items: center; - color: $color-black; - - .file-name-label { - align-items: center; - flex: 1; - height: 2rem; - margin-left: -0.25rem; - overflow: hidden; - padding-left: 0.25rem; - padding-top: 0.25rem; - text-overflow: ellipsis; - white-space: nowrap; - - .icon-library { - height: 14px; - width: 14px; - fill: $color-gray-20; - margin-left: 0.5rem; - padding-top: 1px; - } - } - - .file-name-edit { - width: 100%; - - input { - margin: 0; - border: none; - border-bottom: 1px solid $color-gray-20; - height: 2rem; - width: 100%; - } - } - } - - .feedback-banner { - color: $color-black; - background: $color-success-lighter; - height: 40px; - display: flex; - align-items: center; - margin: 0 1rem; - - .message { - padding: 0 1rem; - font-size: $fs12; - } - - .icon { - background: $color-success; - height: 40px; - width: 40px; - display: flex; - align-items: center; - justify-content: center; - - svg { - width: 20px; - height: 20px; - fill: $color-white; - } - } - - &.warning { - background: $color-warning-lighter; - .icon { - background: $color-warning; - } - } - } - - .error-message { - margin: 0 2rem; - color: $color-danger; - font-size: $fs12; - font-style: italic; - } - - .progress-message { - margin: 0 2rem; - color: $color-info; - font-size: $fs12; - font-style: italic; - } - - .linked-libraries { - display: flex; - flex-wrap: wrap; - margin-left: 2rem; - - .icon-chain, - .icon-unchain { - width: 10px; - height: 10px; - margin-right: 2px; - } - - .linked-library-tag { - font-size: $fs10; - color: $color-black; - background: #d8f7fe; - border-radius: $br3; - padding: 2px 4px; - display: flex; - align-items: center; - margin: 0.25rem; - - &.error { - background-color: $color-danger-lighter; - } - } - } - - .edit-entry-buttons { - display: flex; - flex-direction: row; - font-size: $fs14; - height: 2rem; - display: none; - - button { - border: none; - background: none; - display: block; - cursor: pointer; - - svg { - width: 14px; - height: 14px; - } - - &:hover svg { - fill: $color-primary; - } - } - } -} - -.export-dialog { - .export-option { - border-radius: $br4; - border: 1px solid $color-gray-10; - margin-bottom: 0.5rem; - - h3 { - font-weight: $fw700; - } - - h3, - p { - font-size: $fs12; - line-height: $lh-150; - margin: 0; - color: $color-black; - padding: 0; - } - - &.selected { - border: 1px solid $color-primary; - } - - &.table-row { - align-items: center; - display: flex; - flex-wrap: wrap; - height: 45px; - justify-content: space-between; - padding: 0px 0px; - width: 100%; - } - - .table-field { - flex-grow: 0; - padding: 0px 4px; - overflow: hidden; - text-overflow: ellipsis; - width: 50px; - - &.check { - width: 30px; - } - - &.scale { - flex-grow: 1; - width: 15%; - } - - &.name { - flex-grow: 1; - width: 40%; - } - } - } - - .option-container { - display: block; - position: relative; - padding-left: 40px; - padding-right: 1rem; - padding-top: 1rem; - padding-bottom: 1rem; - cursor: pointer; - user-select: none; - - input { - position: absolute; - opacity: 0; - cursor: pointer; - height: 0; - width: 0; - } - - .option-radio-check { - position: absolute; - top: 1rem; - left: 12px; - height: 18px; - width: 18px; - background-color: $color-white; - border: 1px solid $color-gray-10; - border-radius: 50%; - } - - &:hover input ~ .option-radio-check { - border-color: $color-primary; - } - - input:checked ~ .option-radio-check { - border-color: $color-primary; - background-color: $color-white; - } - - .option-radio-check:after { - content: ""; - position: absolute; - display: none; - } - - input:checked ~ .option-radio-check:after { - display: block; - background-color: $color-primary; - } - - .option-radio-check:after { - top: 3px; - left: 3px; - width: 10px; - height: 10px; - border-radius: 50%; - background: white; - } - } -} - -.libraries-dialog { - border-radius: $br5; - height: 664px; - width: 920px; - max-height: 100%; - - .modal-content { - display: flex; - flex-grow: 1; - flex-direction: column; - padding: 0; - } - - .libraries-header { - border-bottom: 1px solid $color-gray-20; - padding: 2rem 1rem 0.5rem 1rem; - display: flex; - justify-content: center; - - .header-item { - cursor: pointer; - color: $color-gray-40; - font-size: $fs14; - - &.active { - color: $color-gray-60; - border-bottom: 2px solid $color-primary; - } - - &:not(:first-child) { - margin-left: 3rem; - } - } - } - - .libraries-content { - display: flex; - justify-content: stretch; - align-items: stretch; - flex-grow: 1; - padding: 0 $size-4; - color: $color-gray-40; - - .section { - flex-basis: 0; - flex-grow: 1; - padding: $size-4 0; - display: flex; - flex-direction: column; - - &:not(:first-child) { - border-left: 1px solid $color-gray-20; - } - } - - .section-title { - color: $color-black; - font-size: $fs14; - padding: 0 $size-4; - font-weight: $fw500; - } - - .section-list { - flex-basis: 0; - flex-grow: 1; - padding: 0 $size-4; - overflow: auto; - - .section-list-item { - padding: $size-4 0; - border-bottom: 1px solid $color-gray-20; - position: relative; - - .item-name { - color: $color-gray-60; - font-size: $fs14; - margin-right: calc(4.5rem + 1rem); - } - - .item-contents { - color: $color-gray-40; - font-size: $fs12; - margin-right: calc(4.5rem + 1rem); - } - - .item-button { - cursor: pointer; - top: $size-4; - right: 0; - border: 1px solid $color-primary; - border-radius: $br2; - min-width: 4.5rem; - background: $color-primary; - color: $color-black; - padding: $size-2; - margin-bottom: 0; - position: absolute; - top: 1rem; - - &:hover { - color: $color-primary; - background: $color-black; - } - - &.item-update { - background: $color-warning; - border-color: $color-warning; - color: $color-black; - - &.disabled { - background: $color-gray-10; - border-color: $color-gray-10; - color: $color-black; - cursor: unset; - } - } - } - } - } - - .section-list-empty { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding: 0 $size-4; - flex-grow: 1; - - & svg { - fill: $color-gray-20; - height: 50px; - width: 50px; - margin-bottom: $size-4; - } - - & svg#loader-pencil { - fill: $color-gray-20; - height: 75px; - width: 75px; - margin-bottom: $size-4; - } - } - - .libraries-search { - border: 1px solid $color-gray-20; - margin: $size-4; - padding: $size-1 $size-2; - display: flex; - align-items: center; - - &:focus-within { - border-color: $color-primary; - } - - & .search-input { - border: none; - color: $color-gray-60; - font-size: $fs12; - margin: 0; - padding: 0; - flex-grow: 1; - - &:hover, - &:focus { - outline: none; - } - } - - & .search-icon { - display: flex; - align-items: center; - - svg { - fill: $color-gray-30; - height: 16px; - width: 16px; - } - - &.search-close { - transform: rotate(45deg); - cursor: pointer; - } - } - } - - .libraries-updates { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); - grid-gap: $size-5; - font-size: $fs12; - margin-top: $size-4; - - .libraries-updates-item { - display: flex; - align-items: center; - - &:not(:first-child) { - margin-top: $size-2; - } - - & svg { - background-color: $color-canvas; - border-radius: $br4; - border: 2px solid transparent; - height: 24px; - width: 24px; - min-height: 24px; - min-width: 24px; - margin-right: $size-2; - } - - & .color-bullet { - margin-right: $size-2; - } - - & .typography-sample { - margin-right: $size-2; - } - - & .name-block { - color: $color-gray-20; - width: calc(100% - 24px - #{$size-2}); - - &.ellipsis { - padding-left: calc(24px + #{$size-2}); - } - } - - & .item-name { - display: block; - margin: 0; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - } - } - - .libraries-updates-see-all { - margin-top: $size-2; - direction: rtl; - & input { - border: none; - color: $color-info; - cursor: pointer; - margin-bottom: 0; - text-decoration: underline; - } - } - } -} - -//- ONBOARDING -.onboarding { - background-color: $color-white; - box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2); - display: flex; - max-height: 710px; - min-height: 420px; - flex-direction: row; - font-family: "sourcesanspro", sans-serif; - min-width: 620px; - position: relative; - - .modal-left { - align-items: center; - background-color: $color-pink; - border-top-left-radius: $br5; - border-bottom-left-radius: $br5; - display: flex; - flex-shrink: 0; - justify-content: center; - overflow: hidden; - padding: $size-6; - width: 230px; - - &.welcome { - padding: 0; - } - } - - .modal-right { - border-top-right-radius: $br5; - border-bottom-right-radius: $br5; - display: flex; - flex-direction: column; - padding: $size-6; - - .modal-title h2 { - color: $color-black; - font-size: $fs24; - font-weight: $fw900; - } - - .release { - background-color: $color-primary; - color: $color-black; - font-size: $fs12; - font-weight: $fw700; - margin-top: $size-2; - padding: 2px $size-1; - width: max-content; - } - - .modal-content { - border: none; - padding: $size-5 0; - - p { - color: $color-black; - font-size: $fs16; - margin-top: $size-2; - } - } - - .modal-navigation { - align-items: center; - display: flex; - margin-top: auto; - - .skip { - cursor: pointer; - font-family: "worksans", sans-serif; - font-size: $fs12; - margin-left: $size-5; - - &:hover { - color: $color-black; - } - } - } - - .step-dots { - align-items: center; - display: flex; - margin-bottom: 0; - margin-left: auto; - - li { - background-color: $color-gray-10; - border-radius: 50%; - cursor: pointer; - height: $size-2; - margin-left: $size-2; - width: $size-2; - - &.current { - background-color: $color-primary; - } - } - } - } - - &.onboarding-v2 { - min-height: unset; - height: 100%; - min-width: 752px; - .modal-left { - background-color: $color-gray-50; - width: 297px; - } - - .welcome img { - width: 297px; - height: 464px; - position: absolute; - bottom: 0; - border-radius: $br5; - } - - .modal-right { - padding: 0; - } - - .release-container { - width: 100%; - text-align: right; - position: relative; - height: 2rem; - } - - .release { - background-color: $color-primary; - border-radius: $br4; - color: #1f1f1f; - padding: 4px $size-1; - display: inline-block; - margin-top: 1rem; - margin-right: 1rem; - } - - .right-content { - padding: $size-6; - - .modal-content { - padding: $size-1 0; - p { - margin-top: 0.4rem; - } - } - - .welcome-card { - display: flex; - color: $color-black; - margin-top: $size-5; - width: 90%; - - .title a { - font-weight: $fw700; - color: $color-black; - text-decoration: none; - &:hover { - color: $color-primary-dark; - } - } - - .description { - font-size: $fs12; - text-decoration: none; - text-transform: none; - } - - img { - width: 48px; - height: 48px; - margin-right: 6px; - } - } - } - - .modal-navigation { - width: 100%; - padding: 0 2rem 2rem 0; - - button { - margin-left: auto; - padding: 0 0.5rem; - } - } - } - - &.black { - .modal-left { - background-color: $color-black; - } - } - - button { - font-family: "worksans", sans-serif; - } - - &.feature { - .modal-left { - padding: 0; - - img { - border-top-left-radius: $br5; - border-bottom-left-radius: $br5; - height: 100%; - width: 115%; - } - } - } - - &.final { - // TODO: Juan revisa TODA esta parte - - padding: $size-5 0 0 0; - flex-direction: column; - - .modal-top { - padding: 40px 40px 0 40px; - color: $color-gray-60; - display: flex; - flex-direction: column; - align-items: center; - - h1 { - font-family: "worksans", sans-serif; - font-weight: $fw700; - font-size: $fs26; - margin-bottom: $size-3; - text-align: center; - } - p { - font-family: "worksans", sans-serif; - font-weight: $fw500; - font-size: $fs18; - text-align: center; - } - } - - .modal-columns { - display: flex; - margin: 17px; - - .modal-left { - background-image: url("/images/on-solo.svg"); - background-position: left top; - background-size: 11%; - } - - .modal-left:hover { - background-image: url("/images/on-solo-hover.svg"); - background-size: 15%; - } - - .modal-right { - background-image: url("/images/on-teamup.svg"); - background-position: right top; - background-size: 28%; - } - - .modal-right:hover { - background-image: url("/images/on-teamup-hover.svg"); - background-size: 32%; - } - - .modal-right, - .modal-left { - background-repeat: no-repeat; - border-radius: $br5; - transition: all ease 0.3s; - &:hover { - background-color: $color-primary; - } - } - } - - .modal-left { - margin-right: 35px; - } - - .modal-left, - .modal-right { - justify-content: center; - align-items: center; - background-color: $color-white; - color: $color-black; - flex: 1; - flex-direction: column; - // overflow: visible; - // padding: $size-6 40px; - text-align: center; - - border: 1px solid $color-gray-10; - border-radius: $br2; - min-height: 180px; - width: 233px; - cursor: pointer; - - h2 { - font-weight: $fw700; - margin-bottom: $size-5; - font-size: $fs24; - } - - p { - font-size: $fs14; - } - - img { - box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.25); - border-radius: $br5; - margin-bottom: $size-6; - margin-top: -90px; - width: 150px; - } - } - } - - &.newsletter { - padding: $size-5 0 0 0; - flex-direction: column; - min-width: 623px; - .modal-top { - padding: 87px 40px 0 40px; - color: $color-gray-60; - display: flex; - flex-direction: column; - - h1 { - font-family: sourcesanspro; - font-weight: $fw700; - font-size: $fs36; - margin-bottom: 0.75rem; - } - - p { - font-family: sourcesanspro; - font-weight: $fw500; - font-size: $fs16; - margin-bottom: 1.5rem; - } - } - - .modal-bottom { - margin: 0 32px; - padding: 32px 0; - color: $color-gray-60; - display: flex; - flex-direction: column; - border-top: 1px solid $color-gray-10; - - .input-checkbox { - margin-bottom: 23px; - - label { - font-family: "worksans", sans-serif; - text-align: left; - color: $color-black; - font-size: $fs12; - } - } - - p { - font-family: "worksans", sans-serif; - text-align: left; - color: $color-gray-30; - } - } - - .modal-footer { - padding: 17px; - display: flex; - justify-content: flex-end; - - .btn-secondary { - margin-right: 16px; - } - } - - .deco.top { - width: 183px; - top: -106px; - left: 213px; - } - } -} - -.deco { - left: -10px; - position: absolute; - top: -18px; - width: 60px; - - &.left { - left: -50px; - top: 100px; - color: $color-primary; - } - - &.right { - left: auto; - color: $color-primary; - top: 100px; - right: -40px; - } - - &.square { - top: -18px; - left: 631px; - width: 24px; - height: 24px; - color: $color-primary; - } - - &.circle { - top: -16px; - left: 21px; - width: 24px; - height: 24px; - color: $color-primary; - } - - &.line1 { - top: 110px; - left: -12px; - width: 16px; - height: 49px; - color: $color-primary; - } - - &.line2 { - top: 440px; - left: 733px; - width: 46px; - height: 43px; - color: $color-primary; - } - - &.top { - width: 183px; - top: -106px; - left: 161px; - } - - &.newsletter-right { - left: 586px; - top: 50px; - } - - &.newsletter-left { - width: 26px; - left: -15px; - top: -15px; - } -} - -.relnotes .onboarding { - height: 420px; -} - -.onboarding-templates { - position: fixed; - top: 0; - right: 0; - width: 348px; - height: 100vh; - - .modal-close-button { - width: 34px; - height: 34px; - margin-right: 13px; - margin-top: 13px; - svg { - width: 24px; - height: 24px; - } - } - - .modal-header { - height: unset; - border-radius: unset; - justify-content: flex-end; - } - - .modal-content { - border: 0px; - padding: 0px 25px; - background-color: $color-white; - flex-grow: 1; - - p, - h3 { - color: $color-gray-60; - text-align: center; - } - - h3 { - font-size: $fs18; - font-weight: $fw700; - } - - p { - font-size: $fs16; - } - - .templates { - display: flex; - flex-direction: column; - align-items: center; - margin-top: 8%; - } - - .template-item { - width: 275px; - border: 1px solid $color-gray-10; - - display: flex; - flex-direction: column; - text-align: left; - border-radius: $br3; - - &:not(:last-child) { - margin-bottom: 22px; - } - } - - .template-item-content { - // height: 144px; - flex-grow: 1; - - img { - border-radius: $br3 $br3 0 0; - } - } - - .template-item-title { - padding: 6px 12px; - height: 64px; - border-top: 1px solid $color-gray-10; - - .label { - color: $color-black; - padding: 0px 4px; - font-size: $fs16; - display: flex; - } - - .action { - color: $color-primary-dark; - cursor: pointer; - font-size: $fs14; - font-weight: $fw600; - display: flex; - justify-content: flex-end; - margin-top: $size-2; - } - } - } -} - -.onboarding-team, -.onboarding-team-members { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - min-width: 620px; - min-height: 420px; - width: 816px; - height: 488px; - position: relative; - .team-right { - width: 361px; - height: 100%; - background-color: $color-gray-50; - padding: 64px; - display: flex; - flex-direction: column; - justify-content: space-between; - border-radius: 0 $br5 $br5 0; - .subtitle { - font-weight: $fw700; - font-size: $fs20; - color: $color-gray-10; - text-transform: uppercase; - margin-bottom: 8px; - } - .info { - font-size: $fs14; - color: $color-gray-20; - margin-bottom: 32px; - } - .team-features { - flex-grow: 1; - display: flex; - justify-content: space-between; - flex-direction: column; - margin-bottom: 0; - .feature { - display: flex; - align-items: center; - .icon { - display: flex; - align-items: center; - justify-content: center; - background: #31efb8; - min-width: 28px; - width: 28px; - height: 28px; - border-radius: 50%; - - svg { - height: 16px; - width: 16px; - fill: $color-black; - } - } - .feature-txt { - margin: 0; - margin-left: 13px; - color: $color-white; - font-size: $fs14; - display: flex; - align-items: center; - } - } - } - } - .team-left { - width: 455px; - height: 100%; - padding: 64px; - display: flex; - flex-direction: column; - justify-content: space-between; - .title { - font-size: $fs26; - font-weight: $fw700; - color: $color-gray-60; - margin-bottom: 8px; - } - .info { - font-size: $fs14; - color: $color-black; - } - form { - flex-grow: 1; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; - row-gap: 1.5rem; - .custom-input { - width: 100%; - } - .btn-disabled { - color: $color-gray-40; - opacity: 100%; - } - .invite-row { - width: 100%; - .role-wrapper { - display: flex; - justify-content: space-between; - width: 100%; - margin-bottom: 8px; - .rol { - display: flex; - justify-content: center; - align-items: center; - font-size: $fs12; - color: $color-gray-60; - } - } - .custom-input { - height: 96px; - } - .custom-select { - width: 180px; - overflow: hidden; - justify-content: normal; - select { - height: auto; - } - } - - svg { - width: 12px; - height: 12px; - fill: $color-gray-20; - } - } - .buttons { - margin-top: 32px; - width: 100%; - display: grid; - grid-template-columns: 1fr auto; - gap: 8px; - .btn-primary { - max-width: 250px; - } - } - } - .skip-action { - background-color: transparent; - border: none; - text-align: left; - font-size: $fs12; - color: $color-gray-30; - } - } - - .paginator { - width: 32px; - height: 24px; - background-color: $color-gray-60; - position: absolute; - top: 16px; - right: 16px; - display: flex; - justify-content: center; - align-items: center; - font-size: $fs12; - } - .deco { - &.line2 { - top: 422px; - left: 798px; - } - &.square { - top: -14px; - left: 483px; - } - &.line1 { - top: 357px; - } - } -} - -.onboarding-team-members { - .team-left { - form { - align-items: stretch; - margin-top: 24px; - row-gap: normal; - .invite-row { - .custom-input { - width: 100%; - min-height: 80px; - height: fit-content; - max-height: 176px; - overflow-y: hidden; - input { - &.no-padding { - padding-top: 12px; - } - min-height: 40px; - } - .selected-items { - gap: 7px; - padding: 7px; - max-height: 132px; - overflow-y: scroll; - .selected-item { - .around { - height: 24px; - display: flex; - align-items: center; - justify-content: flex-start; - width: fit-content; - .icon { - display: flex; - align-items: center; - justify-content: center; - } - } - } - } - } - } - .buttons { - margin: 32px 0 16px 0; - button { - height: auto; - } - input { - white-space: break-spaces; - word-break: break-word; - height: fit-content; - margin: 0; - padding: 5px 10px; - min-height: 40px; - max-height: 90px; - } - } - } - } -} - -.questions-form { - .modal-overlay { - z-index: 2001; - } - - .modal-container { - display: flex; - flex-direction: row; - justify-content: center; - - .af-form { - --primary-color: #00c38b; - --input-background-color: #ffffff; - --label-font-size: $fs16; - --field-error-font-color: #e65244; - --message-success-font-color: #49d793; - --message-fail-font-color: #e65244; - --invalid-field-border-color: #e65244; - --dropdown-background-color: #ffffff; - --primary-font-color: #000; - --input-border-color: rgb(224, 230, 240); - --input-border-radius: $br3; - --button-border-radius: $br3; - --message-border-radius: $br3; - --checkbox-border-radius: $br3; - --dropdown-option-background-color: rgba(0, 195, 139, 1); - --dropdown-option-active-background-color: rgba(0, 138, 98, 1); - --invalid-field-background-color: rgba(238.51780000000002, 205.7178, 204.11780000000002, 1); - --message-fail-background-color: rgba(238.51780000000002, 205.7178, 204.11780000000002, 1); - --message-success-background-color: rgba(171, 232, 197, 1); - } - } -} - -// Nudge modal - -.nudge-modal-overlay { - display: flex; - align-items: center; - justify-content: center; - position: fixed; - left: calc(50vw - 107px); - top: calc(50vh - 57px); - height: 110px; - width: 215px; - padding: 8px 20px; - background-color: $color-white; - box-shadow: 0px 2px 8px 0px rgb(0 0 0 / 20%); - z-index: 1000; - - &.transparent { - background-color: rgba($color-white, 0); - } - - .nudge-modal-container { - display: flex; - flex-direction: column; - justify-content: space-around; - height: 100%; - width: 100%; - - .nudge-modal-header { - display: flex; - justify-content: space-between; - margin-bottom: 7px; - - .modal-close-button { - display: flex; - justify-content: center; - align-items: center; - background-color: transparent; - border: none; - cursor: pointer; - - svg { - height: 12px; - width: 12px; - transform: rotate(45deg); - } - } - - .nudge-modal-title { - padding: 0; - margin: 0; - color: $color-black; - font-size: $fs12; - } - } - - .nudge-modal-body { - display: flex; - justify-content: space-between; - - .nudge-subtitle { - margin: 0; - } - - input { - width: 72px; - background-color: transparent; - border: none; - border-bottom: 1px solid $color-black; - margin-bottom: 12px; - - &:active, - &:focus, - &:hover { - border-bottom: 1px solid $color-primary; - } - } - } - } -} - -.remove-graphics-dialog { - .modal-content { - padding-top: 16px; - } - - h2 { - font-size: $fs18; - } - - p { - font-size: $fs12; - color: $color-gray-30; - - &:last-child { - margin-bottom: 0; - } - - &.progress-message { - color: $color-info; - } - - &.error-message { - color: $color-black; - - & svg { - width: 16px; - height: 16px; - fill: $color-danger; - margin-right: 0.5rem; - position: relative; - bottom: -4px; - transform: rotate(45deg); - } - } - } - - .close { - border: 1px solid $color-gray-30; - background: $color-canvas; - border-radius: $br3; - padding: 0.5rem 1rem; - cursor: pointer; - margin-right: 8px; - - &:hover { - background: $color-gray-20; - } - } - - .button-primary { - background: $color-primary; - border: 1px solid $color-primary; - border-radius: $br3; - color: $color-black; - cursor: pointer; - padding: 0.5rem 1rem; - - &:hover { - background: $color-primary-dark; - } - } - - .button-secondary { - border: 1px solid $color-gray-30; - background: $color-white; - border-radius: $br3; - padding: 0.5rem 1rem; - cursor: pointer; - margin-right: 8px; - - &:hover { - background: $color-gray-20; - } - } -} - -//- LOGIN -.login-register { - background-color: $color-white; - box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2); - display: flex; - font-family: "worksans", sans-serif; - width: 472px; - height: 100%; - max-height: 700px; - position: relative; - overflow: auto; - position: relative; - - .title { - margin-left: 32px; - h2 { - font-size: $fs24; - color: $color-black; - line-height: $lh-150; // Original value was 2.25rem = 36px; 36px/24px = 150% => $lh-150 - letter-spacing: 0px; - margin: 0 30px 20px 0; - } - - .modal-close-button { - margin-top: 7px; - margin-right: 12px; - justify-content: right; - svg { - fill: $color-black; - } - } - } - - .modal-bottom { - margin: 0 32px; - color: #1f1f1f; - display: flex; - flex-direction: column; - - &.auth-content { - align-items: initial; - height: auto; - .links { - margin: 7px 0 0 0; - text-align: left; - } - } - } - - .modal-footer { - justify-content: center; - align-items: center; - - .terms-login { - position: relative; - bottom: 0; - span { - margin: 0 $size-2; - } - } - } - - .hint { - color: #b1b2b5; - } -} diff --git a/frontend/resources/styles/main/partials/share-link.scss b/frontend/resources/styles/main/partials/share-link.scss deleted file mode 100644 index 8b1d0225f0..0000000000 --- a/frontend/resources/styles/main/partials/share-link.scss +++ /dev/null @@ -1,243 +0,0 @@ -.share-modal { - background: none; - display: block; - top: 50px; - left: calc(100vw - 500px); - - .share-link-dialog { - width: 480px; - background-color: $color-white; - box-shadow: 0px 2px 8px 0px rgb(0 0 0 / 20%); - - .modal-content { - padding: 16px 32px; - &:first-child { - border-top: 0px; - padding: 0; - height: 50px; - display: flex; - justify-content: center; - } - - .title { - display: flex; - justify-content: space-between; - align-items: center; - height: 100%; - margin-left: 32px; - h2 { - font-size: $fs18; - color: $color-black; - } - - .modal-close-button { - margin-right: 16px; - } - } - - .share-link-section { - .custom-input { - display: flex; - flex-direction: row; - margin-bottom: 15px; - border: 1px solid $color-gray-20; - input { - padding: 0 0 0 15px; - border: none; - } - } - .hint-wrapper { - display: flex; - justify-content: space-between; - align-items: center; - .hint { - font-size: $fs12; - color: $color-gray-40; - } - .confirm-dialog { - display: flex; - flex-direction: column; - background-color: unset; - .actions { - display: flex; - justify-content: flex-end; - gap: 16px; - } - .description { - font-size: $fs12; - margin-bottom: 16px; - color: $color-black; - } - .btn-primary, - .btn-secondary, - .btn-warning, - .btn-danger { - width: 126px; - margin-bottom: 0px; - - &:not(:last-child) { - margin-right: 10px; - } - } - } - } - - label { - font-size: $fs12; - color: $color-black; - } - - .help-icon { - height: 40px; - width: 40px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - position: relative; - right: 0; - top: 0; - background-color: $color-gray-10; - border-left: 1px solid $color-gray-20; - svg { - fill: $color-gray-30; - } - &:hover { - background-color: $color-primary; - svg { - fill: $color-gray-60; - } - } - } - input { - margin: 0; - } - } - - &.ops-section { - .manage-permissions { - display: flex; - color: $color-primary-dark; - font-size: $fs12; - cursor: pointer; - .icon { - svg { - height: 16px; - width: 16px; - fill: $color-primary-dark; - } - } - .title { - margin-left: 8px; - } - } - .view-mode { - min-height: 34px; - .subtitle { - height: 32px; - } - .row { - display: flex; - justify-content: space-between; - align-items: center; - .count-pages { - font-size: $fs12; - color: $color-gray-30; - } - } - .current-tag { - font-size: $fs12; - color: $color-gray-30; - } - label { - color: $color-black; - } - } - .access-mode, - .inspect-mode { - display: grid; - grid-template-columns: auto 1fr; - .items { - display: flex; - justify-content: flex-end; - align-items: center; - } - } - .view-mode, - .access-mode, - .inspect-mode { - margin: 8px 0; - .subtitle { - display: flex; - justify-content: flex-start; - align-items: center; - color: $color-black; - font-size: $fs16; - .icon { - display: flex; - justify-content: center; - align-items: center; - margin-right: 10px; - svg { - height: 16px; - width: 16px; - } - } - } - .items { - .input-select { - background-image: url("/images/icons/arrow-down.svg"); - margin: 0; - padding-right: 28px; - border: 1px solid $color-gray-10; - max-width: 227px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - > .input-radio { - display: flex; - user-select: none; - margin-top: 0; - margin-bottom: 0; - label { - display: flex; - align-items: center; - color: $color-black; - max-width: 115px; - - &::before { - height: 16px; - width: 16px; - } - .hint { - margin-left: 5px; - color: $color-gray-30; - } - } - - &.disabled { - label { - color: $color-gray-30; - } - } - } - } - } - - .pages-selection { - border-top: 1px solid $color-gray-10; - border-bottom: 1px solid $color-gray-10; - padding-left: 20px; - max-height: 200px; - overflow-y: scroll; - user-select: none; - - label { - color: $color-black; - } - } - } - } - } -} diff --git a/frontend/resources/styles/main/partials/sidebar-document-history.scss b/frontend/resources/styles/main/partials/sidebar-document-history.scss deleted file mode 100644 index 582d7f300d..0000000000 --- a/frontend/resources/styles/main/partials/sidebar-document-history.scss +++ /dev/null @@ -1,139 +0,0 @@ -// 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 - -// .history-debug-overlay { -// background: $color-gray-50; -// bottom: 0; -// max-height: 500px; -// overflow-y: auto; -// position: absolute; -// width: 500px; -// z-index: 1000; -// } - -// .history-toolbox { -// display: flex; -// flex-direction: column; -// } - -// .history-toolbox-title { -// color: $color-gray-10; -// font-size: $fs14; -// padding: 0.5rem; -// } - -// .history-entry-empty { -// display: flex; -// flex-direction: column; -// align-items: center; -// padding: 1rem; - -// .history-entry-empty-icon { -// margin-bottom: 1rem; -// svg { -// width: 32px; -// height: 32px; -// fill: $color-gray-40; -// } -// } - -// .history-entry-empty-msg { -// color: $color-gray-30; -// font-size: $fs12; -// } -// } - -// .history-entries { -// font-size: $fs12; -// color: $color-gray-20; -// fill: $color-gray-20; -// height: 100%; -// overflow-x: hidden; -// overflow-y: auto; -// } - -// .history-entry { -// border: 1px solid $color-gray-60; -// border-radius: $br4; -// margin: 0.5rem; -// display: flex; -// flex-direction: column; -// padding: 0.5rem; -// cursor: pointer; - -// transition: border 0.2s; - -// &.disabled { -// opacity: 0.5; -// } - -// &.current { -// background-color: $color-gray-60; -// } - -// &.hover { -// border-color: $color-primary; -// } -// } - -// .history-entry-summary { -// display: flex; -// flex-direction: row; -// align-items: center; - -// * { -// display: flex; -// } -// } - -// .history-entry-summary-icon { -// svg { -// width: 16px; -// height: 16px; -// } -// } - -// .history-entry-summary-text { -// flex: 1; -// margin: 0 0.5rem; -// margin-top: 2px; -// } - -// .history-entry-summary-button { -// opacity: 0; -// transition: transform 0.2s; - -// svg { -// width: 12px; -// height: 12px; -// } - -// .show-detail &, -// .hover & { -// opacity: 1; -// } - -// .show-detail & { -// transform: rotate(90deg); -// } -// } - -// .history-entry-detail { -// display: none; - -// .show-detail & { -// display: block; -// padding: 1rem 0 0.5rem 0; -// } - -// .history-entry-details-list { -// margin: 0; - -// li { -// margin-bottom: 0.5rem; -// } -// } -// } diff --git a/frontend/src/app/main/ui/auth/recovery.cljs b/frontend/src/app/main/ui/auth/recovery.cljs index e8828c0031..f43b939bc4 100644 --- a/frontend/src/app/main/ui/auth/recovery.cljs +++ b/frontend/src/app/main/ui/auth/recovery.cljs @@ -12,7 +12,6 @@ [app.main.data.users :as du] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [cljs.spec.alpha :as s] @@ -57,73 +56,41 @@ (mf/defc recovery-form [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - form (fm/use-form :spec ::recovery-form + (let [form (fm/use-form :spec ::recovery-form :validators [password-equality (fm/validate-not-empty :password-1 (tr "auth.password-not-empty")) (fm/validate-not-empty :password-2 (tr "auth.password-not-empty"))] :initial params)] - (if new-css-system - [:& fm/form {:on-submit on-submit :form form} - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "password" - :name :password-1 - :show-success? true - :label (tr "auth.new-password") - :class (stl/css :form-field)}]] + [:& fm/form {:on-submit on-submit :form form} + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "password" + :name :password-1 + :show-success? true + :label (tr "auth.new-password") + :class (stl/css :form-field)}]] - [:div {:class (stl/css :fields-row)} - [:& fm/input {:type "password" - :name :password-2 - :show-success? true - :label (tr "auth.confirm-password") - :class (stl/css :form-field)}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input {:type "password" + :name :password-2 + :show-success? true + :label (tr "auth.confirm-password") + :class (stl/css :form-field)}]] - [:> fm/submit-button* - {:label (tr "auth.recovery-submit") - :class (stl/css :submit-btn)}]] - - ;; OLD - [:& fm/form {:on-submit on-submit - :form form} - [:div.fields-row - [:& fm/input {:type "password" - :name :password-1 - :label (tr "auth.new-password")}]] - - [:div.fields-row - [:& fm/input {:type "password" - :name :password-2 - :label (tr "auth.confirm-password")}]] - - [:> fm/submit-button* - {:label (tr "auth.recovery-submit")}]]))) + [:> fm/submit-button* + {:label (tr "auth.recovery-submit") + :class (stl/css :submit-btn)}]])) ;; --- Recovery Request Page (mf/defc recovery-page [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :auth-form)} - [:h1 {:class (stl/css :auth-title)} "Forgot your password?"] - [:div {:class (stl/css :auth-subtitle)} "Please enter your new password"] - [:hr {:class (stl/css :separator)}] - [:& recovery-form {:params params}] + [:div {:class (stl/css :auth-form)} + [:h1 {:class (stl/css :auth-title)} "Forgot your password?"] + [:div {:class (stl/css :auth-subtitle)} "Please enter your new password"] + [:hr {:class (stl/css :separator)}] + [:& recovery-form {:params params}] - [:div {:class (stl/css :links)} - [:div {:class (stl/css :link-entry)} - [:a {:on-click #(st/emit! (rt/nav :auth-login))} - (tr "profile.recovery.go-to-login")]]]] - - ;; TODO - [:section.generic-form - [:div.form-container - [:h1 "Forgot your password?"] - [:div.subtitle "Please enter your new password"] - [:& recovery-form {:params params}] - - [:div.links - [:div.link-entry - [:a {:on-click #(st/emit! (rt/nav :auth-login))} - (tr "profile.recovery.go-to-login")]]]]]))) + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry)} + [:a {:on-click #(st/emit! (rt/nav :auth-login))} + (tr "profile.recovery.go-to-login")]]]]) diff --git a/frontend/src/app/main/ui/auth/verify_token.cljs b/frontend/src/app/main/ui/auth/verify_token.cljs index db8f7745ac..e0dcd7cfed 100644 --- a/frontend/src/app/main/ui/auth/verify_token.cljs +++ b/frontend/src/app/main/ui/auth/verify_token.cljs @@ -11,7 +11,6 @@ [app.main.data.users :as du] [app.main.repo :as rp] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.static :as static] [app.util.dom :as dom] @@ -62,8 +61,7 @@ (mf/defc verify-token [{:keys [route] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - token (get-in route [:query-params :token]) + (let [token (get-in route [:query-params :token]) bad-token (mf/use-state false)] (mf/with-effect [] @@ -96,6 +94,5 @@ (if @bad-token [:> static/invalid-token {}] - [:div {:class (stl/css-case :verify-token new-css-system - :global/verify-token (not new-css-system))} + [:div {:class (stl/css :verify-token)} i/loader-pencil]))) diff --git a/frontend/src/app/main/ui/components/code_block.cljs b/frontend/src/app/main/ui/components/code_block.cljs index d6d81f8495..b766772344 100644 --- a/frontend/src/app/main/ui/components/code_block.cljs +++ b/frontend/src/app/main/ui/components/code_block.cljs @@ -8,7 +8,6 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] - [app.main.ui.context :as ctx] [cuerdas.core :as str] [promesa.core :as p] [rumext.v2 :as mf] @@ -20,8 +19,7 @@ (mf/defc code-block {::mf/wrap-props false} [{:keys [code type]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - block-ref (mf/use-ref) + (let [block-ref (mf/use-ref) code (str/trim code)] (mf/with-effect [code type] @@ -29,7 +27,5 @@ (p/let [highlight-fn (lazy/load highlight-fn)] (highlight-fn node)))) - (if new-css-system - [:pre {:class (dm/str type " " (stl/css :code-display)) :ref block-ref} code] - [:pre {:class (dm/str type " " "code-display") :ref block-ref} code]))) + [:pre {:class (dm/str type " " (stl/css :code-display)) :ref block-ref} code])) diff --git a/frontend/src/app/main/ui/components/context_menu_a11y.cljs b/frontend/src/app/main/ui/components/context_menu_a11y.cljs index 1b8bc1c610..e6a230bf58 100644 --- a/frontend/src/app/main/ui/components/context_menu_a11y.cljs +++ b/frontend/src/app/main/ui/components/context_menu_a11y.cljs @@ -11,7 +11,6 @@ [app.common.data.macros :as dm] [app.main.refs :as refs] [app.main.ui.components.dropdown :refer [dropdown']] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -68,7 +67,6 @@ min-width? (gobj/get props "min-width?" false) origin (gobj/get props "origin") route (mf/deref refs/route) - new-css-system (mf/use-ctx ctx/new-css-system) in-dashboard? (= :dashboard-projects (:name (:data route))) local (mf/use-state {:offset-y 0 :offset-x 0 @@ -191,149 +189,79 @@ (tm/schedule-on-idle #(dom/focus! (dom/get-element (first ids))))) - (if new-css-system - (when (and open? (some? (:levels @local))) - [:> dropdown' props - (let [level (-> @local :levels peek) - original-options (:options level) - parent-original (:parent-option level)] - [:div {:class (stl/css-case :is-selectable is-selectable - :context-menu true - :is-open open? - :fixed fixed?) - :style {:top (+ top (:offset-y @local)) - :left (+ left (:offset-x @local))} - :on-key-down (on-key-down original-options parent-original)} - (let [level (-> @local :levels peek)] - [:ul {:class (stl/css-case :min-width min-width? - :context-menu-items true) - :role "menu" - :ref check-menu-offscreen} - (when-let [parent-option (:parent-option level)] - [:* - [:& context-menu-a11y-item - {:id "go-back-sub-option" - :class (stl/css :context-menu-item) - :tab-index "0" - :on-key-down (fn [event] - (dom/prevent-default event))} - [:button {:class (stl/css :context-menu-action :submenu-back) + (when (and open? (some? (:levels @local))) + [:> dropdown' props + (let [level (-> @local :levels peek) + original-options (:options level) + parent-original (:parent-option level)] + [:div {:class (stl/css-case :is-selectable is-selectable + :context-menu true + :is-open open? + :fixed fixed?) + :style {:top (+ top (:offset-y @local)) + :left (+ left (:offset-x @local))} + :on-key-down (on-key-down original-options parent-original)} + (let [level (-> @local :levels peek)] + [:ul {:class (stl/css-case :min-width min-width? + :context-menu-items true) + :role "menu" + :ref check-menu-offscreen} + (when-let [parent-option (:parent-option level)] + [:* + [:& context-menu-a11y-item + {:id "go-back-sub-option" + :class (stl/css :context-menu-item) + :tab-index "0" + :on-key-down (fn [event] + (dom/prevent-default event))} + [:button {:class (stl/css :context-menu-action :submenu-back) + :data-no-close true + :on-click exit-submenu} + [:span {:class (stl/css :submenu-icon-back)} i/arrow-refactor] + parent-option]] + + [:li {:class (stl/css :separator)}]]) + + (for [[index option] (d/enumerate (:options level))] + (let [option-name (:option-name option) + id (:id option) + sub-options (:sub-options option) + option-handler (:option-handler option) + data-test (:data-test option)] + (when option-name + (if (= option-name :separator) + [:li {:key (dm/str "context-item-" index) + :class (stl/css :separator)}] + [:& context-menu-a11y-item + {:id id + :key id + :class (stl/css-case + :is-selected (and selected (= option-name selected)) + :selected (and selected (= data-test selected)) + :context-menu-item true) + :key-index (dm/str "context-item-" index) + :tab-index "0" + :on-key-down (fn [event] + (dom/prevent-default event))} + (if-not sub-options + [:a {:class (stl/css :context-menu-action) + :on-click #(do (dom/stop-propagation %) + (on-close) + (option-handler %)) + :data-test data-test} + (if (and in-dashboard? (= option-name "Default")) + (tr "dashboard.default-team-name") + option-name) + + (when (and selected (= data-test selected)) + [:span {:class (stl/css :selected-icon)} i/tick-refactor])] + + [:a {:class (stl/css :context-menu-action :submenu) :data-no-close true - :on-click exit-submenu} - [:span {:class (stl/css :submenu-icon-back)} i/arrow-refactor] - parent-option]] - - [:li {:class (stl/css :separator)}]]) - - (for [[index option] (d/enumerate (:options level))] - (let [option-name (:option-name option) - id (:id option) - sub-options (:sub-options option) - option-handler (:option-handler option) - data-test (:data-test option)] - (when option-name - (if (= option-name :separator) - [:li {:key (dm/str "context-item-" index) - :class (stl/css :separator)}] - [:& context-menu-a11y-item - {:id id - :key id - :class (stl/css-case - :is-selected (and selected (= option-name selected)) - :selected (and selected (= data-test selected)) - :context-menu-item true) - :key-index (dm/str "context-item-" index) - :tab-index "0" - :on-key-down (fn [event] - (dom/prevent-default event))} - (if-not sub-options - [:a {:class (stl/css :context-menu-action) - :on-click #(do (dom/stop-propagation %) - (on-close) - (option-handler %)) - :data-test data-test} - (if (and in-dashboard? (= option-name "Default")) - (tr "dashboard.default-team-name") - option-name) - - (when (and selected (= data-test selected)) - [:span {:class (stl/css :selected-icon)} i/tick-refactor])] - - [:a {:class (stl/css :context-menu-action :submenu) - :data-no-close true - :on-click (enter-submenu option-name sub-options) - :data-test data-test} - option-name - [:span {:class (stl/css :submenu-icon)} i/arrow-refactor]])]))))])])]) - - ;; OLD - (when (and open? (some? (:levels @local))) - [:> dropdown' props - - (let [level (-> @local :levels peek) - original-options (:options level) - parent-original (:parent-option level)] - [:div {:class (dom/classnames :is-selectable is-selectable - :context-menu true - :is-open open? - :fixed fixed?) - :style {:top (+ top (:offset-y @local)) - :left (+ left (:offset-x @local))} - :on-key-down (on-key-down original-options parent-original)} - (let [level (-> @local :levels peek)] - [:ul {:class (dom/classnames :min-width min-width? - :context-menu-items true) - :role "menu" - :ref check-menu-offscreen} - (when-let [parent-option (:parent-option level)] - [:* - [:& context-menu-a11y-item - {:id "go-back-sub-option" - :tab-index "0" - :on-key-down (fn [event] - (dom/prevent-default event))} - [:div {:class (dom/classnames :context-menu-action true - :submenu-back true) - :data-no-close true - :on-click exit-submenu} - [:span i/arrow-slide] - - parent-option]] - - [:li.separator]]) - - (for [[index option] (d/enumerate (:options level))] - (let [option-name (:option-name option) - id (:id option) - sub-options (:sub-options option) - option-handler (:option-handler option) - data-test (:data-test option)] - (when option-name - (if (= option-name :separator) - [:li.separator {:key (dm/str "context-item-" index)}] - [:& context-menu-a11y-item - {:id id - :key id - :class (dom/classnames :is-selected (and selected (= option-name selected))) - :key-index (dm/str "context-item-" index) - :tab-index "0" - :on-key-down (fn [event] - (dom/prevent-default event))} - (if-not sub-options - [:a {:class (dom/classnames :context-menu-action true) - :on-click #(do (dom/stop-propagation %) - (on-close) - (option-handler %)) - :data-test data-test} - (if (and in-dashboard? (= option-name "Default")) - (tr "dashboard.default-team-name") - option-name)] - [:a.context-menu-action.submenu - {:data-no-close true - :on-click (enter-submenu option-name sub-options) - :data-test data-test} - option-name - [:span i/arrow-slide]])]))))])])])))) + :on-click (enter-submenu option-name sub-options) + :data-test data-test} + option-name + [:span {:class (stl/css :submenu-icon)} i/arrow-refactor]])]))))])])]))) (mf/defc context-menu-a11y {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/components/forms.cljs b/frontend/src/app/main/ui/components/forms.cljs index 11b633cc86..70469c23a1 100644 --- a/frontend/src/app/main/ui/components/forms.cljs +++ b/frontend/src/app/main/ui/components/forms.cljs @@ -386,21 +386,19 @@ (mf/defc submit-button* {::mf/wrap-props false} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - form (or (unchecked-get props "form") + (let [form (or (unchecked-get props "form") (mf/use-ctx form-ctx)) label (unchecked-get props "label") on-click (unchecked-get props "onClick") children (unchecked-get props "children") - class (d/nilv (unchecked-get props "className") "btn-primary btn-large") + class (unchecked-get props "className") name (d/nilv (unchecked-get props "name") "submit") disabled? (or (and (some? form) (not (:valid @form))) (true? (unchecked-get props "disabled"))) - klass (dm/str class " " (if disabled? "btn-disabled" "")) new-klass (dm/str class " " (if disabled? (stl/css :btn-disabled) "")) on-key-down @@ -416,7 +414,7 @@ (obj/set! "onKeyDown" on-key-down) (obj/set! "name" name) (obj/set! "label" mf/undefined) - (obj/set! "className" (if new-css-system new-klass klass)) + (obj/set! "className" new-klass) (obj/set! "type" "submit"))] [:> "button" props diff --git a/frontend/src/app/main/ui/components/tab_container.cljs b/frontend/src/app/main/ui/components/tab_container.cljs index 9b52965a56..be104cfcf6 100644 --- a/frontend/src/app/main/ui/components/tab_container.cljs +++ b/frontend/src/app/main/ui/components/tab_container.cljs @@ -9,7 +9,6 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :refer [tr]] @@ -19,9 +18,8 @@ (mf/defc tab-element {::mf/wrap-props false} [props] - (let [children (unchecked-get props "children") - new-css-system (mf/use-ctx ctx/new-css-system)] - [:div {:class (stl/css new-css-system :tab-element)} + (let [children (unchecked-get props "children")] + [:div {:class (stl/css :tab-element)} children])) (mf/defc tab-container diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index 6905c68bc0..ec956fa08e 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -53,8 +53,7 @@ (mf/defc dashboard-content [{:keys [team projects project section search-term profile] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - container (mf/use-ref) + (let [container (mf/use-ref) content-width (mf/use-state 0) project-id (:id project) team-id (:id team) @@ -82,123 +81,65 @@ (mf/use-effect on-resize) - (if new-css-system - [:div {:class (stl/css :dashboard-content) - :on-click clear-selected-fn :ref container} - (case section - :dashboard-projects - [:* - [:& projects-section - {:team team - :projects projects - :profile profile - :default-project-id default-project-id}] + [:div {:class (stl/css :dashboard-content) + :on-click clear-selected-fn :ref container} + (case section + :dashboard-projects + [:* + [:& projects-section + {:team team + :projects projects + :profile profile + :default-project-id default-project-id}] + (when (contains? cf/flags :dashboard-templates-section) + [:& templates-section {:profile profile + :project-id project-id + :team-id team-id + :default-project-id default-project-id + :content-width @content-width}])] + + :dashboard-fonts + [:& fonts-page {:team team}] + + :dashboard-font-providers + [:& font-providers-page {:team team}] + + :dashboard-files + (when project + [:* + [:& files-section {:team team :project project}] (when (contains? cf/flags :dashboard-templates-section) [:& templates-section {:profile profile - :project-id project-id :team-id team-id - :default-project-id default-project-id - :content-width @content-width}])] - - :dashboard-fonts - [:& fonts-page {:team team}] - - :dashboard-font-providers - [:& font-providers-page {:team team}] - - :dashboard-files - (when project - [:* - [:& files-section {:team team :project project}] - (when (contains? cf/flags :dashboard-templates-section) - [:& templates-section {:profile profile - :team-id team-id - :project-id project-id - :default-project-id default-project-id - :content-width @content-width}])]) - - :dashboard-search - [:& search-page {:team team - :search-term search-term}] - - :dashboard-libraries - [:& libraries-page {:team team}] - - :dashboard-team-members - [:& team-members-page {:team team :profile profile}] - - :dashboard-team-invitations - [:& team-invitations-page {:team team}] - - :dashboard-team-webhooks - [:& team-webhooks-page {:team team}] - - :dashboard-team-settings - [:& team-settings-page {:team team :profile profile}] - - nil)] - - ;; OLD - [:div.dashboard-content {:on-click clear-selected-fn :ref container} - (case section - :dashboard-projects - [:* - [:& projects-section - {:team team - :projects projects - :profile profile - :default-project-id default-project-id}] - - (when (contains? cf/flags :dashboard-templates-section) - [:& templates-section {:profile profile :project-id project-id - :team-id team-id :default-project-id default-project-id - :content-width @content-width}])] + :content-width @content-width}])]) - :dashboard-fonts - [:& fonts-page {:team team}] + :dashboard-search + [:& search-page {:team team + :search-term search-term}] - :dashboard-font-providers - [:& font-providers-page {:team team}] + :dashboard-libraries + [:& libraries-page {:team team}] - :dashboard-files - (when project - [:* - [:& files-section {:team team :project project}] - (when (contains? cf/flags :dashboard-templates-section) - [:& templates-section {:profile profile - :team-id team-id - :project-id project-id - :default-project-id default-project-id - :content-width @content-width}])]) + :dashboard-team-members + [:& team-members-page {:team team :profile profile}] - :dashboard-search - [:& search-page {:team team - :search-term search-term}] + :dashboard-team-invitations + [:& team-invitations-page {:team team}] - :dashboard-libraries - [:& libraries-page {:team team}] + :dashboard-team-webhooks + [:& team-webhooks-page {:team team}] - :dashboard-team-members - [:& team-members-page {:team team :profile profile}] + :dashboard-team-settings + [:& team-settings-page {:team team :profile profile}] - :dashboard-team-invitations - [:& team-invitations-page {:team team}] - - :dashboard-team-webhooks - [:& team-webhooks-page {:team team}] - - :dashboard-team-settings - [:& team-settings-page {:team team :profile profile}] - - nil)]))) + nil)])) (mf/defc dashboard [{:keys [route profile] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - section (get-in route [:data :name]) + (let [section (get-in route [:data :name]) params (parse-params route) project-id (:project-id params) @@ -227,59 +168,31 @@ (fn [] (events/unlistenByKey key)))) - (if new-css-system - [:& (mf/provider ctx/current-team-id) {:value team-id} - [:& (mf/provider ctx/current-project-id) {:value project-id} - ;; NOTE: dashboard events and other related functions assumes - ;; that the team is a implicit context variable that is - ;; available using react context or accessing - ;; the :current-team-id on the state. We set the key to the - ;; team-id because we want to completely refresh all the - ;; components on team change. Many components assumes that the - ;; team is already set so don't put the team into mf/deps. - (when team - [:main {:class (stl/css :dashboard) - :key (:id team)} - [:& sidebar - {:team team - :projects projects - :project project + [:& (mf/provider ctx/current-team-id) {:value team-id} + [:& (mf/provider ctx/current-project-id) {:value project-id} + ;; NOTE: dashboard events and other related functions assumes + ;; that the team is a implicit context variable that is + ;; available using react context or accessing + ;; the :current-team-id on the state. We set the key to the + ;; team-id because we want to completely refresh all the + ;; components on team change. Many components assumes that the + ;; team is already set so don't put the team into mf/deps. + (when team + [:main {:class (stl/css :dashboard) + :key (:id team)} + [:& sidebar + {:team team + :projects projects + :project project + :profile profile + :section section + :search-term search-term}] + (when (and team profile (seq projects)) + [:& dashboard-content + {:projects projects :profile profile - :section section - :search-term search-term}] - (when (and team profile (seq projects)) - [:& dashboard-content - {:projects projects - :profile profile - :project project - :section section - :search-term search-term - :team team}])])]] - - [:& (mf/provider ctx/current-team-id) {:value team-id} - [:& (mf/provider ctx/current-project-id) {:value project-id} - ;; NOTE: dashboard events and other related functions assumes - ;; that the team is a implicit context variable that is - ;; available using react context or accessing - ;; the :current-team-id on the state. We set the key to the - ;; team-id because we want to completely refresh all the - ;; components on team change. Many components assumes that the - ;; team is already set so don't put the team into mf/deps. - (when team - [:main {:class (dom/classnames :dashboard-layout true) :key (:id team)} - [:& sidebar - {:team team - :projects projects :project project - :profile profile :section section - :search-term search-term}] - (when (and team profile (seq projects)) - [:& dashboard-content - {:projects projects - :profile profile - :project project - :section section - :search-term search-term - :team team}])])]]))) + :search-term search-term + :team team}])])]])) diff --git a/frontend/src/app/main/ui/dashboard/comments.cljs b/frontend/src/app/main/ui/dashboard/comments.cljs index 45c4d75d60..fcc5502517 100644 --- a/frontend/src/app/main/ui/dashboard/comments.cljs +++ b/frontend/src/app/main/ui/dashboard/comments.cljs @@ -14,9 +14,7 @@ [app.main.store :as st] [app.main.ui.comments :as cmt] [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] - [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [potok.v2.core :as ptk] @@ -42,21 +40,18 @@ (on-show-comments event))))] [:div {:class (stl/css :dashboard-comments-section)} - [:button - {:tab-index "0" - :on-click on-show-comments - :on-key-down handle-keydown - :data-test "open-comments" - :class (stl/css-case :button true - :open show? - :unread (boolean (seq tgroups)))} - i/chat]])) + [:button {:tab-index "0" + :on-click on-show-comments + :on-key-down handle-keydown + :data-test "open-comments" + :class (stl/css-case :button true + :open show? + :unread (boolean (seq tgroups)))} + i/comments-refactor]])) (mf/defc comments-section - [{:keys [profile team show? on-show-comments on-hide-comments]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - threads-map (mf/deref refs/comment-threads) + [{:keys [profile team show? on-hide-comments]}] + (let [threads-map (mf/deref refs/comment-threads) users (mf/deref refs/current-team-comments-users) team-id (:id team) @@ -91,79 +86,32 @@ (st/emit! (ptk/event ::ev/event {::ev/name "open-comment-notifications" ::ev/origin "dashboard"}))))) - (if new-css-system - [:div {:class (stl/css :dashboard-comments-section)} - [:& dropdown {:show show? :on-close on-hide-comments} - [:div {:class (stl/css :dropdown :comments-section :comment-threads-section)} - [:div {:class (stl/css :header)} - [:h3 (tr "labels.comments")] - [:button - {:class (stl/css :close) - :tab-index (if show? "0" "-1") - :on-click on-hide-comments - :on-key-down handle-keydown} i/close]] + [:div {:class (stl/css :dashboard-comments-section)} + [:& dropdown {:show show? :on-close on-hide-comments} + [:div {:class (stl/css :dropdown :comments-section :comment-threads-section)} + [:div {:class (stl/css :header)} + [:h3 (tr "labels.comments")] + [:button + {:class (stl/css :close) + :tab-index (if show? "0" "-1") + :on-click on-hide-comments + :on-key-down handle-keydown} i/close]] - (if (seq tgroups) - [:div {:class (stl/css :thread-groups)} + (if (seq tgroups) + [:div {:class (stl/css :thread-groups)} + [:& cmt/comment-thread-group + {:group (first tgroups) + :on-thread-click on-navigate + :show-file-name true + :users users}] + (for [tgroup (rest tgroups)] [:& cmt/comment-thread-group - {:group (first tgroups) + {:group tgroup :on-thread-click on-navigate :show-file-name true - :users users}] - (for [tgroup (rest tgroups)] - [:& cmt/comment-thread-group - {:group tgroup - :on-thread-click on-navigate - :show-file-name true - :users users - :key (:page-id tgroup)}])] + :users users + :key (:page-id tgroup)}])] - [:div {:class (stl/css :thread-groups-placeholder)} - i/chat - (tr "labels.no-comments-available")])]]] - - ;; OLD - [:div.dashboard-comments-section - [:div.button - {:tab-index "0" - :on-click on-show-comments - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-show-comments event))) - :data-test "open-comments" - :class (dom/classnames :open show? - :unread (boolean (seq tgroups)))} - i/chat] - - [:& dropdown {:show show? :on-close on-hide-comments} - [:div.dropdown.comments-section.comment-threads-section. - [:div.header - [:h3 (tr "labels.comments")] - [:span.close {:tab-index (if show? "0" "-1") - :on-click on-hide-comments - :on-key-down handle-keydown} - i/close]] - - [:hr] - - (if (seq tgroups) - [:div.thread-groups - [:& cmt/comment-thread-group - {:group (first tgroups) - :on-thread-click on-navigate - :show-file-name true - :users users}] - (for [tgroup (rest tgroups)] - [:* - [:hr] - - [:& cmt/comment-thread-group - {:group tgroup - :on-thread-click on-navigate - :show-file-name true - :users users - :key (:page-id tgroup)}]])] - - [:div.thread-groups-placeholder - i/chat - (tr "labels.no-comments-available")])]]]))) + [:div {:class (stl/css :thread-groups-placeholder)} + i/comments-refactor + (tr "labels.no-comments-available")])]]])) diff --git a/frontend/src/app/main/ui/dashboard/comments.scss b/frontend/src/app/main/ui/dashboard/comments.scss index ed615fa73a..395d08005d 100644 --- a/frontend/src/app/main/ui/dashboard/comments.scss +++ b/frontend/src/app/main/ui/dashboard/comments.scss @@ -47,9 +47,11 @@ font-size: $fs-12; padding: $s-24; text-align: center; + color: $df-secondary; svg { - fill: $df-secondary; + stroke: $df-secondary; + fill: none; height: $s-24; margin-bottom: $s-24; width: $s-24; @@ -65,21 +67,22 @@ width: $s-32; svg { - width: $s-16; - height: $s-16; - fill: $df-secondary; + min-width: $s-16; + min-height: $s-16; + stroke: $df-secondary; + fill: none; } &.unread svg, &.open svg { - fill: $da-tertiary; + stroke: $da-tertiary; } &:hover { background-color: $db-cuaternary; svg { - fill: $da-primary; + stroke: $da-primary; } } } diff --git a/frontend/src/app/main/ui/dashboard/files.cljs b/frontend/src/app/main/ui/dashboard/files.cljs index 7faf96b97e..afbeb5afc4 100644 --- a/frontend/src/app/main/ui/dashboard/files.cljs +++ b/frontend/src/app/main/ui/dashboard/files.cljs @@ -11,7 +11,6 @@ [app.main.data.events :as ev] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.grid :refer [grid]] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] [app.main.ui.dashboard.project-menu :refer [project-menu]] @@ -26,8 +25,7 @@ (mf/defc header [{:keys [project create-fn] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - local (mf/use-state + (let [local (mf/use-state {:menu-open false :edition false}) @@ -64,137 +62,75 @@ (dd/clear-selected-files))))] - (if new-css-system - [:header {:class (stl/css :dashboard-header)} - (if (:is-default project) - [:div#dashboard-drafts-title {:class (stl/css :dashboard-title)} - [:h1 (tr "labels.drafts")]] + [:header {:class (stl/css :dashboard-header)} + (if (:is-default project) + [:div#dashboard-drafts-title {:class (stl/css :dashboard-title)} + [:h1 (tr "labels.drafts")]] - (if (:edition @local) - [:& inline-edition - {:content (:name project) - :on-end (fn [name] - (let [name (str/trim name)] - (when-not (str/empty? name) - (st/emit! (-> (dd/rename-project (assoc project :name name)) - (with-meta {::ev/origin "project"})))) - (swap! local assoc :edition false)))}] - [:div {:class (stl/css :dashboard-title)} - [:h1 {:on-double-click on-edit - :data-test "project-title" - :id (:id project)} - (:name project)]])) + (if (:edition @local) + [:& inline-edition + {:content (:name project) + :on-end (fn [name] + (let [name (str/trim name)] + (when-not (str/empty? name) + (st/emit! (-> (dd/rename-project (assoc project :name name)) + (with-meta {::ev/origin "project"})))) + (swap! local assoc :edition false)))}] + [:div {:class (stl/css :dashboard-title)} + [:h1 {:on-double-click on-edit + :data-test "project-title" + :id (:id project)} + (:name project)]])) - [:& project-menu {:project project - :show? (:menu-open @local) - :left (- (:x (:menu-pos @local)) 180) - :top (:y (:menu-pos @local)) - :on-edit on-edit - :on-menu-close on-menu-close - :on-import on-import}] + [:& project-menu {:project project + :show? (:menu-open @local) + :left (- (:x (:menu-pos @local)) 180) + :top (:y (:menu-pos @local)) + :on-edit on-edit + :on-menu-close on-menu-close + :on-import on-import}] - [:div {:class (stl/css :dashboard-header-actions)} - [:a - {:class (stl/css :btn-secondary :btn-small) + [:div {:class (stl/css :dashboard-header-actions)} + [:a + {:class (stl/css :btn-secondary :btn-small) + :tab-index "0" + :on-click on-create-click + :data-test "new-file" + :on-key-down (fn [event] + (when (kbd/enter? event) + (on-create-click event)))} + (tr "dashboard.new-file")] + + (when-not (:is-default project) + [:button + {:class (stl/css-case :icon true + :pin-icon true + :tooltip true + :tooltip-bottom true + :active (:is-pinned project)) :tab-index "0" - :on-click on-create-click - :data-test "new-file" + :on-click toggle-pin + :alt (tr "dashboard.pin-unpin") :on-key-down (fn [event] (when (kbd/enter? event) - (on-create-click event)))} - (tr "dashboard.new-file")] + (toggle-pin event)))} + (if (:is-pinned project) + i/pin-fill + i/pin)]) - (when-not (:is-default project) - [:button - {:class (stl/css-case :icon true - :pin-icon true - :tooltip true - :tooltip-bottom true - :active (:is-pinned project)) - :tab-index "0" - :on-click toggle-pin - :alt (tr "dashboard.pin-unpin") - :on-key-down (fn [event] - (when (kbd/enter? event) - (toggle-pin event)))} - (if (:is-pinned project) - i/pin-fill - i/pin)]) - - [:div - {:class (stl/css :icon :tooltip :tooltip-bottom-left) - :tab-index "0" - :on-click on-menu-click - :alt (tr "dashboard.options") - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-menu-click event)))} - i/actions]]] - - ;; OLD - [:header.dashboard-header - (if (:is-default project) - [:div.dashboard-title#dashboard-drafts-title - [:h1 (tr "labels.drafts")]] - - (if (:edition @local) - [:& inline-edition {:content (:name project) - :on-end (fn [name] - (let [name (str/trim name)] - (when-not (str/empty? name) - (st/emit! (-> (dd/rename-project (assoc project :name name)) - (with-meta {::ev/origin "project"})))) - (swap! local assoc :edition false)))}] - [:div.dashboard-title - [:h1 {:on-double-click on-edit - :data-test "project-title" - :id (:id project)} - (:name project)]])) - - [:& project-menu {:project project - :show? (:menu-open @local) - :left (- (:x (:menu-pos @local)) 180) - :top (:y (:menu-pos @local)) - :on-edit on-edit - :on-menu-close on-menu-close - :on-import on-import}] - - [:div.dashboard-header-actions - [:a.btn-secondary.btn-small - {:tab-index "0" - :on-click on-create-click - :data-test "new-file" - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-create-click event)))} - (tr "dashboard.new-file")] - - (when-not (:is-default project) - [:button.icon.pin-icon.tooltip.tooltip-bottom - {:tab-index "0" - :class (when (:is-pinned project) "active") - :on-click toggle-pin - :alt (tr "dashboard.pin-unpin") - :on-key-down (fn [event] - (when (kbd/enter? event) - (toggle-pin event)))} - (if (:is-pinned project) - i/pin-fill - i/pin)]) - - [:div.icon.tooltip.tooltip-bottom-left - {:tab-index "0" - :on-click on-menu-click - :alt (tr "dashboard.options") - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-menu-click event)))} - i/actions]]]))) + [:div + {:class (stl/css :icon :tooltip :tooltip-bottom-left) + :tab-index "0" + :on-click on-menu-click + :alt (tr "dashboard.options") + :on-key-down (fn [event] + (when (kbd/enter? event) + (on-menu-click event)))} + i/actions]]])) (mf/defc files-section [{:keys [project team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - files-map (mf/deref refs/dashboard-files) + (let [files-map (mf/deref refs/dashboard-files) project-id (:id project) [rowref limit] (hooks/use-dynamic-grid-item-width) @@ -233,28 +169,15 @@ (st/emit! (dd/fetch-files {:project-id project-id}) (dd/clear-selected-files))) - (if new-css-system - [:* - [:& header {:team team - :project project - :create-fn create-file}] - [:section {:class (stl/css :dashboard-container :no-bg) - :ref rowref} - [:& grid {:project project - :files files - :origin :files - :create-fn create-file - :limit limit}]]] - - ;; OLD - [:* - [:& header {:team team - :project project - :create-fn create-file}] - [:section.dashboard-container.no-bg {:ref rowref} - [:& grid {:project project - :files files - :origin :files - :create-fn create-file - :limit limit}]]]))) + [:* + [:& header {:team team + :project project + :create-fn create-file}] + [:section {:class (stl/css :dashboard-container :no-bg) + :ref rowref} + [:& grid {:project project + :files files + :origin :files + :create-fn create-file + :limit limit}]]])) diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs index 30cfa5f392..8a5d5a8591 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -15,7 +15,6 @@ [app.main.store :as st] [app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.file-uploader :refer [file-uploader]] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -40,17 +39,10 @@ (mf/defc header {::mf/wrap [mf/memo]} [{:keys [section team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (use-set-page-title team section) - (if new-css-system - [:header {:class (stl/css :dashboard-header)} - [:div#dashboard-fonts-title {:class (stl/css :dashboard-title)} - [:h1 (tr "labels.fonts")]]] - - ;; OLD - [:header.dashboard-header - [:div.dashboard-title#dashboard-fonts-title - [:h1 (tr "labels.fonts")]]]))) + (use-set-page-title team section) + [:header {:class (stl/css :dashboard-header)} + [:div#dashboard-fonts-title {:class (stl/css :dashboard-title)} + [:h1 (tr "labels.fonts")]]]) (mf/defc font-variant-display-name [{:keys [variant]}] @@ -61,8 +53,7 @@ (mf/defc fonts-upload [{:keys [team installed-fonts] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - fonts (mf/use-state {}) + (let [fonts (mf/use-state {}) input-ref (mf/use-ref) uploading (mf/use-state #{}) @@ -121,151 +112,82 @@ handle-dismiss-all (mf/use-callback (mf/deps @fonts) #(on-dismiss-all (vals @fonts)))] - (if new-css-system - [:div {:class (stl/css :dashboard-fonts-upload)} - [:div {:class (stl/css :dashboard-fonts-hero)} - [:div {:class (stl/css :desc)} - [:h2 (tr "labels.upload-custom-fonts")] - [:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}] + [:div {:class (stl/css :dashboard-fonts-upload)} + [:div {:class (stl/css :dashboard-fonts-hero)} + [:div {:class (stl/css :desc)} + [:h2 (tr "labels.upload-custom-fonts")] + [:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}] - [:button - {:class (stl/css :btn-primary) - :on-click on-click - :tab-index "0"} - [:span (tr "labels.add-custom-font")] - [:& file-uploader {:input-id "font-upload" - :accept cm/str-font-types - :multi true - :ref input-ref - :on-selected on-selected}]] + [:button + {:class (stl/css :btn-primary) + :on-click on-click + :tab-index "0"} + [:span (tr "labels.add-custom-font")] + [:& file-uploader {:input-id "font-upload" + :accept cm/str-font-types + :multi true + :ref input-ref + :on-selected on-selected}]] - [:div {:class (stl/css :banner)} - [:div {:class (stl/css :icon)} i/msg-info] + [:div {:class (stl/css :banner)} + [:div {:class (stl/css :icon)} i/msg-info] + [:div {:class (stl/css :content)} + [:& i18n/tr-html {:tag-name "span" + :label "dashboard.fonts.hero-text2"}]]] + + (when problematic-fonts? + [:div {:class (stl/css :banner :warning)} + [:div {:class (stl/css :icon)} i/msg-warning] [:div {:class (stl/css :content)} [:& i18n/tr-html {:tag-name "span" - :label "dashboard.fonts.hero-text2"}]]] + :label "dashboard.fonts.warning-text"}]]])]] - (when problematic-fonts? - [:div {:class (stl/css :banner :warning)} - [:div {:class (stl/css :icon)} i/msg-warning] - [:div {:class (stl/css :content)} - [:& i18n/tr-html {:tag-name "span" - :label "dashboard.fonts.warning-text"}]]])]] + [:* + (when (some? (vals @fonts)) + [:div {:class (stl/css :font-item :table-row)} + [:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals @fonts))))] + [:div {:class (stl/css :table-field :options)} + [:button {:class (stl/css :btn-primary) + :on-click handle-upload-all :data-test "upload-all"} + [:span (tr "dashboard.fonts.upload-all")]] + [:button {:class (stl/css :btn-secondary) + :on-click handle-dismiss-all :data-test "dismiss-all"} + [:span (tr "dashboard.fonts.dismiss-all")]]]]) + + (for [item (sort-by :font-family (vals @fonts))] + (let [uploading? (contains? @uploading (:id item))] + [:div {:class (stl/css :font-item :table-row) :key (:id item)} + [:div {:class (stl/css :table-field :family)} + [:input {:type "text" + :on-blur #(on-blur-name (:id item) %) + :default-value (:font-family item)}]] + [:div {:class (stl/css :table-field :variants)} + [:span {:class (stl/css :label)} + [:& font-variant-display-name {:variant item}]]] + + [:div {:class (stl/css :table-field :filenames)} + (for [item (:names item)] + [:span item])] - [:* - (when (some? (vals @fonts)) - [:div {:class (stl/css :font-item :table-row)} - [:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals @fonts))))] [:div {:class (stl/css :table-field :options)} - [:button {:class (stl/css :btn-primary) - :on-click handle-upload-all :data-test "upload-all"} - [:span (tr "dashboard.fonts.upload-all")]] - [:button {:class (stl/css :btn-secondary) - :on-click handle-dismiss-all :data-test "dismiss-all"} - [:span (tr "dashboard.fonts.dismiss-all")]]]]) + (when (:height-warning? item) + [:span {:class (stl/css :icon :failure)} i/msg-warning]) - (for [item (sort-by :font-family (vals @fonts))] - (let [uploading? (contains? @uploading (:id item))] - [:div {:class (stl/css :font-item :table-row) :key (:id item)} - [:div {:class (stl/css :table-field :family)} - [:input {:type "text" - :on-blur #(on-blur-name (:id item) %) - :default-value (:font-family item)}]] - [:div {:class (stl/css :table-field :variants)} - [:span {:class (stl/css :label)} - [:& font-variant-display-name {:variant item}]]] - - [:div {:class (stl/css :table-field :filenames)} - (for [item (:names item)] - [:span item])] - - [:div {:class (stl/css :table-field :options)} - (when (:height-warning? item) - [:span {:class (stl/css :icon :failure)} i/msg-warning]) - - [:button - {:on-click #(on-upload item) - :class (stl/css-case :btn-primary true - :upload-button true - :disabled uploading?) - :disabled uploading?} - (if uploading? - (tr "labels.uploading") - (tr "labels.upload"))] - [:span {:class (stl/css :icon :close) - :on-click #(on-delete item)} i/close]]]))]] - ;; OLD - [:div.dashboard-fonts-upload - [:div.dashboard-fonts-hero - [:div.desc - [:h2 (tr "labels.upload-custom-fonts")] - [:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}] - - [:div.banner - [:div.icon i/msg-info] - [:div.content - [:& i18n/tr-html {:tag-name "span" - :label "dashboard.fonts.hero-text2"}]]] - - (when problematic-fonts? - [:div.banner.warning - [:div.icon i/msg-warning] - [:div.content - [:& i18n/tr-html {:tag-name "span" - :label "dashboard.fonts.warning-text"}]]])] - - [:button.btn-primary - {:on-click on-click - :tab-index "0"} - [:span (tr "labels.add-custom-font")] - [:& file-uploader {:input-id "font-upload" - :accept cm/str-font-types - :multi true - :ref input-ref - :on-selected on-selected}]]] - - [:* - (when (some? (vals @fonts)) - [:div.font-item.table-row - [:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals @fonts))))] - [:div.table-field.options - [:div.btn-primary - {:on-click #(on-upload-all (vals @fonts)) :data-test "upload-all"} - [:span (tr "dashboard.fonts.upload-all")]] - [:div.btn-secondary - {:on-click #(on-dismiss-all (vals @fonts)) :data-test "dismiss-all"} - [:span (tr "dashboard.fonts.dismiss-all")]]]]) - - (for [item (sort-by :font-family (vals @fonts))] - (let [uploading? (contains? @uploading (:id item))] - [:div.font-item.table-row {:key (:id item)} - [:div.table-field.family - [:input {:type "text" - :on-blur #(on-blur-name (:id item) %) - :default-value (:font-family item)}]] - [:div.table-field.variants - [:span.label - [:& font-variant-display-name {:variant item}]]] - [:div.table-field.filenames - (for [item (:names item)] - [:span item])] - - [:div.table-field.options - (when (:height-warning? item) - [:span.icon.failure i/msg-warning]) - [:button.btn-primary.upload-button - {:on-click #(on-upload item) - :class (dom/classnames :disabled uploading?) - :disabled uploading?} - (if uploading? - (tr "labels.uploading") - (tr "labels.upload"))] - [:span.icon.close {:on-click #(on-delete item)} i/close]]]))]]))) + [:button + {:on-click #(on-upload item) + :class (stl/css-case :btn-primary true + :upload-button true + :disabled uploading?) + :disabled uploading?} + (if uploading? + (tr "labels.uploading") + (tr "labels.upload"))] + [:span {:class (stl/css :icon :close) + :on-click #(on-delete item)} i/close]]]))]])) (mf/defc installed-font [{:keys [font-id variants] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - font (first variants) + (let [font (first variants) variants (sort-by (fn [item] [(:font-weight item) @@ -324,94 +246,52 @@ :on-accept (fn [_props] (delete-variant-fn id))})))] - (if new-css-system - [:div {:class (stl/css :font-item :table-row)} - [:div {:class (stl/css :table-field :family)} - (if @edit? - [:input {:type "text" - :default-value @state - :on-key-down on-key-down - :on-change on-change}] - [:span (:font-family font)])] + [:div {:class (stl/css :font-item :table-row)} + [:div {:class (stl/css :table-field :family)} + (if @edit? + [:input {:type "text" + :default-value @state + :on-key-down on-key-down + :on-change on-change}] + [:span (:font-family font)])] - [:div {:class (stl/css :table-field :variants)} - (for [item variants] - [:div {:class (stl/css :variant)} - [:span {:class (stl/css :label)} - [:& font-variant-display-name {:variant item}]] - [:span - {:class (stl/css :icon :close) - :on-click #(on-delete-variant (:id item))} - i/plus]])] + [:div {:class (stl/css :table-field :variants)} + (for [item variants] + [:div {:class (stl/css :variant)} + [:span {:class (stl/css :label)} + [:& font-variant-display-name {:variant item}]] + [:span + {:class (stl/css :icon :close) + :on-click #(on-delete-variant (:id item))} + i/plus]])] - (if @edit? - [:div {:class (stl/css :table-field :options)} - [:button - {:disabled (str/blank? @state) - :on-click on-save - :class (stl/css-case :btn-primary true - :btn-disabled (str/blank? @state))} - (tr "labels.save")] - [:button {:class (stl/css :icon :close) - :on-click on-cancel} i/close]] + (if @edit? + [:div {:class (stl/css :table-field :options)} + [:button + {:disabled (str/blank? @state) + :on-click on-save + :class (stl/css-case :btn-primary true + :btn-disabled (str/blank? @state))} + (tr "labels.save")] + [:button {:class (stl/css :icon :close) + :on-click on-cancel} i/close]] - [:div {:class (stl/css :table-field :options)} - [:span {:class (stl/css :icon) - :on-click #(reset! open-menu? true)} i/actions] - [:& context-menu - {:on-close #(reset! open-menu? false) - :show @open-menu? - :fixed? false - :top -15 - :left -115 - :options [[(tr "labels.edit") #(reset! edit? true) nil "font-edit"] - [(tr "labels.delete") on-delete nil "font-delete"]]}]])] - ;;OLD - [:div.font-item.table-row - [:div.table-field.family - (if @edit? - [:input {:type "text" - :default-value @state - :on-key-down on-key-down - :on-change on-change}] - [:span (:font-family font)])] - - [:div.table-field.variants - (for [item variants] - [:div.variant - [:span.label - [:& font-variant-display-name {:variant item}]] - [:span.icon.close - {:on-click #(on-delete-variant (:id item))} - i/plus]])] - - [:div] - - (if @edit? - [:div.table-field.options - [:button.btn-primary - {:disabled (str/blank? @state) - :on-click on-save - :class (dom/classnames :btn-disabled (str/blank? @state))} - (tr "labels.save")] - [:span.icon.close {:on-click on-cancel} i/close]] - - [:div.table-field.options - [:span.icon {:on-click #(reset! open-menu? true)} i/actions] - [:& context-menu - {:on-close #(reset! open-menu? false) - :show @open-menu? - :fixed? false - :top -15 - :left -115 - :options [[(tr "labels.edit") #(reset! edit? true) nil "font-edit"] - [(tr "labels.delete") on-delete nil "font-delete"]]}]])]))) + [:div {:class (stl/css :table-field :options)} + [:span {:class (stl/css :icon) + :on-click #(reset! open-menu? true)} i/actions] + [:& context-menu + {:on-close #(reset! open-menu? false) + :show @open-menu? + :fixed? false + :top -15 + :left -115 + :options [[(tr "labels.edit") #(reset! edit? true) nil "font-edit"] + [(tr "labels.delete") on-delete nil "font-delete"]]}]])])) (mf/defc installed-fonts [{:keys [fonts] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - sterm (mf/use-state "") + (let [sterm (mf/use-state "") matches? #(str/includes? (str/lower (:font-family %)) @sterm) @@ -422,98 +302,49 @@ (let [val (dom/get-target-val event)] (reset! sterm (str/lower val)))))] - (if new-css-system - [:div {:class (stl/css :dashboard-installed-fonts)} - [:h3 (tr "labels.installed-fonts")] - [:div {:class (stl/css :installed-fonts-header)} - [:div {:class (stl/css :table-field :family)} (tr "labels.font-family")] - [:div {:class (stl/css :table-field :variants)} (tr "labels.font-variants")] - [:div {:class (stl/css :table-field :search-input)} - [:input {:placeholder (tr "labels.search-font") - :default-value "" - :on-change on-change}]]] + [:div {:class (stl/css :dashboard-installed-fonts)} + [:h3 (tr "labels.installed-fonts")] + [:div {:class (stl/css :installed-fonts-header)} + [:div {:class (stl/css :table-field :family)} (tr "labels.font-family")] + [:div {:class (stl/css :table-field :variants)} (tr "labels.font-variants")] + [:div {:class (stl/css :table-field :search-input)} + [:input {:placeholder (tr "labels.search-font") + :default-value "" + :on-change on-change}]]] - (cond - (seq fonts) - (for [[font-id variants] (->> (vals fonts) - (filter matches?) - (group-by :font-id))] - [:& installed-font {:key (str font-id) - :font-id font-id - :variants variants}]) + (cond + (seq fonts) + (for [[font-id variants] (->> (vals fonts) + (filter matches?) + (group-by :font-id))] + [:& installed-font {:key (str font-id) + :font-id font-id + :variants variants}]) - (nil? fonts) - [:div {:class (stl/css :fonts-placeholder)} - [:div {:class (stl/css :icon)} i/loader] - [:div {:class (stl/css :label)} (tr "dashboard.loading-fonts")]] + (nil? fonts) + [:div {:class (stl/css :fonts-placeholder)} + [:div {:class (stl/css :icon)} i/loader] + [:div {:class (stl/css :label)} (tr "dashboard.loading-fonts")]] - :else - [:div {:class (stl/css :fonts-placeholder)} - [:div {:class (stl/css :icon)} i/text] - [:div {:class (stl/css :label)} (tr "dashboard.fonts.empty-placeholder")]])] - - ;; OLD - [:div.dashboard-installed-fonts - [:h3 (tr "labels.installed-fonts")] - [:div.installed-fonts-header - [:div.table-field.family (tr "labels.font-family")] - [:div.table-field.variants (tr "labels.font-variants")] - [:div] - [:div.table-field.search-input - [:input {:placeholder (tr "labels.search-font") - :default-value "" - :on-change on-change}]]] - - (cond - (seq fonts) - (for [[font-id variants] (->> (vals fonts) - (filter matches?) - (group-by :font-id))] - [:& installed-font {:key (str font-id) - :font-id font-id - :variants variants}]) - - (nil? fonts) - [:div.fonts-placeholder - [:div.icon i/loader] - [:div.label (tr "dashboard.loading-fonts")]] - - :else - [:div.fonts-placeholder - [:div.icon i/text] - [:div.label (tr "dashboard.fonts.empty-placeholder")]])]))) + :else + [:div {:class (stl/css :fonts-placeholder)} + [:div {:class (stl/css :icon)} i/text] + [:div {:class (stl/css :label)} (tr "dashboard.fonts.empty-placeholder")]])])) (mf/defc fonts-page [{:keys [team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - fonts (mf/deref refs/dashboard-fonts)] - (if new-css-system - [:* - [:& header {:team team :section :fonts}] - [:section {:class (stl/css :dashboard-container :dashboard-fonts)} - [:& fonts-upload {:team team :installed-fonts fonts}] - [:& installed-fonts {:team team :fonts fonts}]]] - - ;; OLD - [:* - [:& header {:team team :section :fonts}] - [:section.dashboard-container.dashboard-fonts - [:& fonts-upload {:team team :installed-fonts fonts}] - [:& installed-fonts {:team team :fonts fonts}]]]))) + (let [fonts (mf/deref refs/dashboard-fonts)] + [:* + [:& header {:team team :section :fonts}] + [:section {:class (stl/css :dashboard-container :dashboard-fonts)} + [:& fonts-upload {:team team :installed-fonts fonts}] + [:& installed-fonts {:team team :fonts fonts}]]])) (mf/defc font-providers-page [{:keys [team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:* - [:& header {:team team :section :providers}] - [:section {:class (stl/css :dashboard-container)} - [:span "font providers"]]] - - ;; OLD - [:* - [:& header {:team team :section :providers}] - [:section.dashboard-container - [:span "font providers"]]]))) + [:* + [:& header {:team team :section :providers}] + [:section {:class (stl/css :dashboard-container)} + [:span "font providers"]]]) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 57108c88b2..67dac1f45f 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -20,7 +20,6 @@ [app.main.repo :as rp] [app.main.store :as st] [app.main.ui.components.color-bullet :as bc] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.file-menu :refer [file-menu]] [app.main.ui.dashboard.import :refer [use-import-file]] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] @@ -68,8 +67,7 @@ (mf/defc grid-item-thumbnail {::mf/wrap-props false} [{:keys [file-id revn thumbnail-uri background-color]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - container (mf/use-ref) + (let [container (mf/use-ref) visible? (h/use-visible container :once? true)] (mf/with-effect [file-id revn visible? thumbnail-uri] @@ -83,28 +81,16 @@ :revn revn :message (ex-message cause))))))) - (if new-css-system - [:div {:class (stl/css :grid-item-th) - :style {:background-color background-color} - :ref container} - (when visible? - (if thumbnail-uri - [:img {:class (stl/css :grid-item-thumbnail-image) - :src thumbnail-uri - :loading "lazy" - :decoding "async"}] - i/loader-pencil))] - - ;; OLD - [:div.grid-item-th - {:style {:background-color background-color} - :ref container} - (when visible? - (if thumbnail-uri - [:img.grid-item-thumbnail-image {:src thumbnail-uri - :loading "lazy" - :decoding "async"}] - i/loader-pencil))]))) + [:div {:class (stl/css :grid-item-th) + :style {:background-color background-color} + :ref container} + (when visible? + (if thumbnail-uri + [:img {:class (stl/css :grid-item-thumbnail-image) + :src thumbnail-uri + :loading "lazy" + :decoding "async"}] + i/loader-pencil))])) ;; --- Grid Item Library @@ -112,228 +98,125 @@ {::mf/wrap [mf/memo]} [{:keys [file] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (mf/with-effect [file] - (when file - (let [font-ids (map :font-id (get-in file [:library-summary :typographies :sample] []))] - (run! fonts/ensure-loaded! font-ids)))) + (mf/with-effect [file] + (when file + (let [font-ids (map :font-id (get-in file [:library-summary :typographies :sample] []))] + (run! fonts/ensure-loaded! font-ids)))) - (if new-css-system - [:div {:class (stl/css :grid-item-th :library)} - (if (nil? file) - i/loader-pencil - (let [summary (:library-summary file) - components (:components summary) - colors (:colors summary) - typographies (:typographies summary)] - [:* - (when (and (zero? (:count components)) (zero? (:count colors)) (zero? (:count typographies))) - [:* - [:div {:class (stl/css :asset-section)} - [:div {:class (stl/css :asset-title)} - [:span (tr "workspace.assets.components")] - [:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space - [:div {:class (stl/css :asset-section)} - [:div {:class (stl/css :asset-title)} - [:span (tr "workspace.assets.colors")] - [:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space - [:div {:class (stl/css :asset-section)} - [:div {:class (stl/css :asset-title)} - [:span (tr "workspace.assets.typography")] - [:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]]]) ;; Unicode 00A0 is non-breaking space + [:div {:class (stl/css :grid-item-th :library)} + (if (nil? file) + i/loader-pencil + (let [summary (:library-summary file) + components (:components summary) + colors (:colors summary) + typographies (:typographies summary)] + [:* + (when (and (zero? (:count components)) (zero? (:count colors)) (zero? (:count typographies))) + [:* + [:div {:class (stl/css :asset-section)} + [:div {:class (stl/css :asset-title)} + [:span (tr "workspace.assets.components")] + [:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space + [:div {:class (stl/css :asset-section)} + [:div {:class (stl/css :asset-title)} + [:span (tr "workspace.assets.colors")] + [:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space + [:div {:class (stl/css :asset-section)} + [:div {:class (stl/css :asset-title)} + [:span (tr "workspace.assets.typography")] + [:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]]]) ;; Unicode 00A0 is non-breaking space - (when (pos? (:count components)) - [:div {:class (stl/css :asset-section)} - [:div {:class (stl/css :asset-title)} - [:span (tr "workspace.assets.components")] - [:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count components) ")"]] ;; Unicode 00A0 is non-breaking space - [:div {:class (stl/css :asset-list)} - (for [component (:sample components)] - (let [root-id (or (:main-instance-id component) (:id component))] ;; Check for components-v2 in library - [:div {:class (stl/css :asset-list-item) - :key (str "assets-component-" (:id component))} - [:& component-svg {:root-shape (get-in component [:objects root-id]) - :objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2 - [:div {:class (stl/css :name-block)} - [:span {:class (stl/css :item-name) - :title (:name component)} - (:name component)]]])) - (when (> (:count components) (count (:sample components))) - [:div {:class (stl/css :asset-list-item)} - [:div {:class (stl/css :name-block)} - [:span {:class (stl/css :item-name)} "(...)"]]])]]) + (when (pos? (:count components)) + [:div {:class (stl/css :asset-section)} + [:div {:class (stl/css :asset-title)} + [:span (tr "workspace.assets.components")] + [:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count components) ")"]] ;; Unicode 00A0 is non-breaking space + [:div {:class (stl/css :asset-list)} + (for [component (:sample components)] + (let [root-id (or (:main-instance-id component) (:id component))] ;; Check for components-v2 in library + [:div {:class (stl/css :asset-list-item) + :key (str "assets-component-" (:id component))} + [:& component-svg {:root-shape (get-in component [:objects root-id]) + :objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2 + [:div {:class (stl/css :name-block)} + [:span {:class (stl/css :item-name) + :title (:name component)} + (:name component)]]])) + (when (> (:count components) (count (:sample components))) + [:div {:class (stl/css :asset-list-item)} + [:div {:class (stl/css :name-block)} + [:span {:class (stl/css :item-name)} "(...)"]]])]]) - (when (pos? (:count colors)) - [:div {:class (stl/css :asset-section)} - [:div {:class (stl/css :asset-title)} - [:span (tr "workspace.assets.colors")] - [:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count colors) ")"]] ;; Unicode 00A0 is non-breaking space - [:div {:class (stl/css :asset-list)} - (for [color (:sample colors)] - (let [default-name (cond - (:gradient color) (uc/gradient-type->string (get-in color [:gradient :type])) - (:color color) (:color color) - :else (:value color))] - [:div {:class (stl/css :asset-list-item) - :key (str "assets-color-" (:id color))} - [:& bc/color-bullet {:color {:color (:color color) - :opacity (:opacity color)}}] - [:div {:class (stl/css :name-block)} - [:span {:class (stl/css :color-name)} (:name color)] - (when-not (= (:name color) default-name) - [:span {:class (stl/css :color-value)} (:color color)])]])) + (when (pos? (:count colors)) + [:div {:class (stl/css :asset-section)} + [:div {:class (stl/css :asset-title)} + [:span (tr "workspace.assets.colors")] + [:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count colors) ")"]] ;; Unicode 00A0 is non-breaking space + [:div {:class (stl/css :asset-list)} + (for [color (:sample colors)] + (let [default-name (cond + (:gradient color) (uc/gradient-type->string (get-in color [:gradient :type])) + (:color color) (:color color) + :else (:value color))] + [:div {:class (stl/css :asset-list-item) + :key (str "assets-color-" (:id color))} + [:& bc/color-bullet {:color {:color (:color color) + :opacity (:opacity color)}}] + [:div {:class (stl/css :name-block)} + [:span {:class (stl/css :color-name)} (:name color)] + (when-not (= (:name color) default-name) + [:span {:class (stl/css :color-value)} (:color color)])]])) - (when (> (:count colors) (count (:sample colors))) - [:div {:class (stl/css :asset-list-item)} - [:div {:class (stl/css :name-block)} - [:span {:class (stl/css :item-name)} "(...)"]]])]]) + (when (> (:count colors) (count (:sample colors))) + [:div {:class (stl/css :asset-list-item)} + [:div {:class (stl/css :name-block)} + [:span {:class (stl/css :item-name)} "(...)"]]])]]) - (when (pos? (:count typographies)) - [:div {:class (stl/css :asset-section)} - [:div {:class (stl/css :asset-title)} - [:span (tr "workspace.assets.typography")] - [:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count typographies) ")"]] ;; Unicode 00A0 is non-breaking space - [:div {:class (stl/css :asset-list)} - (for [typography (:sample typographies)] - [:div {:class (stl/css :asset-list-item) - :key (str "assets-typography-" (:id typography))} - [:div {:class (stl/css :typography-sample) - :style {:font-family (:font-family typography) - :font-weight (:font-weight typography) - :font-style (:font-style typography)}} - (tr "workspace.assets.typography.sample")] - [:div {:class (stl/css :name-block)} - [:span {:class (stl/css :item-name) - :title (:name typography)} - (:name typography)]]]) + (when (pos? (:count typographies)) + [:div {:class (stl/css :asset-section)} + [:div {:class (stl/css :asset-title)} + [:span (tr "workspace.assets.typography")] + [:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count typographies) ")"]] ;; Unicode 00A0 is non-breaking space + [:div {:class (stl/css :asset-list)} + (for [typography (:sample typographies)] + [:div {:class (stl/css :asset-list-item) + :key (str "assets-typography-" (:id typography))} + [:div {:class (stl/css :typography-sample) + :style {:font-family (:font-family typography) + :font-weight (:font-weight typography) + :font-style (:font-style typography)}} + (tr "workspace.assets.typography.sample")] + [:div {:class (stl/css :name-block)} + [:span {:class (stl/css :item-name) + :title (:name typography)} + (:name typography)]]]) - (when (> (:count typographies) (count (:sample typographies))) - [:div {:class (stl/css :asset-list-item)} - [:div {:class (stl/css :name-block)} - [:span {:class (stl/css :item-name)} "(...)"]]])]])]))] - - ;; OLD - [:div.grid-item-th.library - (if (nil? file) - i/loader-pencil - (let [summary (:library-summary file) - components (:components summary) - colors (:colors summary) - typographies (:typographies summary)] - [:* - - (when (and (zero? (:count components)) (zero? (:count colors)) (zero? (:count typographies))) - [:* - [:div.asset-section - [:div.asset-title - [:span (tr "workspace.assets.components")] - [:span.num-assets (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space - [:div.asset-section - [:div.asset-title - [:span (tr "workspace.assets.colors")] - [:span.num-assets (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space - [:div.asset-section - [:div.asset-title - [:span (tr "workspace.assets.typography")] - [:span.num-assets (str "\u00A0(") 0 ")"]]]]) ;; Unicode 00A0 is non-breaking space - - - (when (pos? (:count components)) - [:div.asset-section - [:div.asset-title - [:span (tr "workspace.assets.components")] - [:span.num-assets (str "\u00A0(") (:count components) ")"]] ;; Unicode 00A0 is non-breaking space - [:div.asset-list - (for [component (:sample components)] - (let [root-id (or (:main-instance-id component) (:id component))] ;; Check for components-v2 in library - [:div.asset-list-item {:key (str "assets-component-" (:id component))} - [:& component-svg {:root-shape (get-in component [:objects root-id]) - :objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2 - [:div.name-block - [:span.item-name {:title (:name component)} - (:name component)]]])) - (when (> (:count components) (count (:sample components))) - [:div.asset-list-item - [:div.name-block - [:span.item-name "(...)"]]])]]) - - (when (pos? (:count colors)) - [:div.asset-section - [:div.asset-title - [:span (tr "workspace.assets.colors")] - [:span.num-assets (str "\u00A0(") (:count colors) ")"]] ;; Unicode 00A0 is non-breaking space - [:div.asset-list - (for [color (:sample colors)] - (let [default-name (cond - (:gradient color) (uc/gradient-type->string (get-in color [:gradient :type])) - (:color color) (:color color) - :else (:value color))] - [:div.asset-list-item {:key (str "assets-color-" (:id color))} - [:& bc/color-bullet {:color {:color (:color color) - :opacity (:opacity color)}}] - [:div.name-block - [:span.color-name (:name color)] - (when-not (= (:name color) default-name) - [:span.color-value (:color color)])]])) - (when (> (:count colors) (count (:sample colors))) - [:div.asset-list-item - [:div.name-block - [:span.item-name "(...)"]]])]]) - - (when (pos? (:count typographies)) - [:div.asset-section - [:div.asset-title - [:span (tr "workspace.assets.typography")] - [:span.num-assets (str "\u00A0(") (:count typographies) ")"]] ;; Unicode 00A0 is non-breaking space - [:div.asset-list - (for [typography (:sample typographies)] - [:div.asset-list-item {:key (str "assets-typography-" (:id typography))} - [:div.typography-sample - {:style {:font-family (:font-family typography) - :font-weight (:font-weight typography) - :font-style (:font-style typography)}} - (tr "workspace.assets.typography.sample")] - [:div.name-block - [:span.item-name {:title (:name typography)} - (:name typography)]]]) - (when (> (:count typographies) (count (:sample typographies))) - [:div.asset-list-item - [:div.name-block - [:span.item-name "(...)"]]])]])]))]))) + (when (> (:count typographies) (count (:sample typographies))) + [:div {:class (stl/css :asset-list-item)} + [:div {:class (stl/css :name-block)} + [:span {:class (stl/css :item-name)} "(...)"]]])]])]))]) ;; --- Grid Item (mf/defc grid-item-metadata [{:keys [modified-at]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - locale (mf/deref i18n/locale) + (let [locale (mf/deref i18n/locale) time (dt/timeago modified-at {:locale locale})] - (if new-css-system - [:span {:class (stl/css :date)} time] - - ;; OLD - [:span.date time]))) + [:span {:class (stl/css :date)} time])) (defn create-counter-element - [_element file-count new-css-system] - (if new-css-system - (let [counter-el (dom/create-element "div")] - (dom/set-property! counter-el "class" (stl/css :drag-counter)) - (dom/set-text! counter-el (str file-count)) - counter-el) - - (let [counter-el (dom/create-element "div")] - (dom/set-property! counter-el "class" "drag-counter") - (dom/set-text! counter-el (str file-count)) - counter-el))) + [_element file-count] + (let [counter-el (dom/create-element "div")] + (dom/set-property! counter-el "class" (stl/css :drag-counter)) + (dom/set-text! counter-el (str file-count)) + counter-el)) (mf/defc grid-item {:wrap [mf/memo]} [{:keys [file navigate? origin library-view?] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - file-id (:id file) + (let [file-id (:id file) local (mf/use-state {:menu-open false :menu-pos nil :edition false}) @@ -380,8 +263,7 @@ item-el (if select-current? 1 - (count selected-files)) - new-css-system)] + (count selected-files)))] (when select-current? (st/emit! (dd/clear-selected-files)) (st/emit! (dd/toggle-file-select file))) @@ -453,132 +335,67 @@ (when (and (not selected?) (:menu-open @local)) (swap! local assoc :menu-open false))) - (if new-css-system - [:li - {:class (stl/css-case :grid-item true :project-th true :library library-view?)} - [:button - {:class (stl/css-case :selected selected? :library library-view?) - :ref node-ref - :title (:name file) - :draggable true - :on-click on-select - :on-key-down handle-key-down - :on-double-click on-navigate - :on-drag-start on-drag-start - :on-context-menu on-menu-click} + [:li + {:class (stl/css-case :grid-item true :project-th true :library library-view?)} + [:button + {:class (stl/css-case :selected selected? :library library-view?) + :ref node-ref + :title (:name file) + :draggable true + :on-click on-select + :on-key-down handle-key-down + :on-double-click on-navigate + :on-drag-start on-drag-start + :on-context-menu on-menu-click} - [:div {:class (stl/css :overlay)}] + [:div {:class (stl/css :overlay)}] - (if library-view? - [:& grid-item-library {:file file}] - [:& grid-item-thumbnail - {:file-id (:id file) - :revn (:revn file) - :thumbnail-uri (:thumbnail-uri file) - :background-color (dm/get-in file [:data :options :background])}]) + (if library-view? + [:& grid-item-library {:file file}] + [:& grid-item-thumbnail + {:file-id (:id file) + :revn (:revn file) + :thumbnail-uri (:thumbnail-uri file) + :background-color (dm/get-in file [:data :options :background])}]) - (when (and (:is-shared file) (not library-view?)) - [:div {:class (stl/css :item-badge)} i/library]) + (when (and (:is-shared file) (not library-view?)) + [:div {:class (stl/css :item-badge)} i/library]) - [:div {:class (stl/css :info-wrapper)} - [:div {:class (stl/css :item-info)} - (if (:edition @local) - [:& inline-edition {:content (:name file) - :on-end edit}] - [:h3 (:name file)]) - [:& grid-item-metadata {:modified-at (:modified-at file)}]] + [:div {:class (stl/css :info-wrapper)} + [:div {:class (stl/css :item-info)} + (if (:edition @local) + [:& inline-edition {:content (:name file) + :on-end edit}] + [:h3 (:name file)]) + [:& grid-item-metadata {:modified-at (:modified-at file)}]] - [:div {:class (stl/css-case :project-th-actions true :force-display (:menu-open @local))} - [:div - {:class (stl/css :project-th-icon :menu) - :tab-index "0" - :ref menu-ref - :id (str file-id "-action-menu") - :on-click on-menu-click - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/stop-propagation event) - (on-menu-click event)))} - i/actions - (when selected? - [:& file-menu {:files (vals selected-files) - :show? (:menu-open @local) - :left (+ 24 (:x (:menu-pos @local))) - :top (:y (:menu-pos @local)) - :navigate? navigate? - :on-edit on-edit - :on-menu-close on-menu-close - :origin origin - :dashboard-local dashboard-local - :parent-id (str file-id "-action-menu")}])]]]]] - - ;; OLD - [:li.grid-item.project-th {:class (dom/classnames :library library-view?)} - [:button - {:tab-index "0" - :class (dom/classnames :selected selected? - :library library-view?) - :ref node-ref - :draggable true - :on-click on-select - :on-key-down (fn [event] - (dom/stop-propagation event) - (when (kbd/enter? event) - (on-navigate event)) - (when (kbd/shift? event) - (when (or (kbd/down-arrow? event) (kbd/left-arrow? event) (kbd/up-arrow? event) (kbd/right-arrow? event)) - (on-select event)) ;; TODO Fix this - )) - :on-double-click on-navigate - :on-drag-start on-drag-start - :on-context-menu on-menu-click} - - [:div.overlay] - (if library-view? - [:& grid-item-library {:file file}] - [:& grid-item-thumbnail - {:file-id (:id file) - :revn (:revn file) - :thumbnail-uri (:thumbnail-uri file) - :background-color (dm/get-in file [:data :options :background])}]) - - (when (and (:is-shared file) (not library-view?)) - [:div.item-badge i/library]) - [:div.info-wrapper - [:div.item-info - (if (:edition @local) - [:& inline-edition {:content (:name file) - :on-end edit}] - [:h3 (:name file)]) - [:& grid-item-metadata {:modified-at (:modified-at file)}]] - [:div.project-th-actions {:class (dom/classnames - :force-display (:menu-open @local))} - [:div.project-th-icon.menu - {:tab-index "0" - :ref menu-ref - :id (str file-id "-action-menu") - :on-click on-menu-click - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/stop-propagation event) - (on-menu-click event)))} - i/actions - (when selected? - [:& file-menu {:files (vals selected-files) - :show? (:menu-open @local) - :left (+ 24 (:x (:menu-pos @local))) - :top (:y (:menu-pos @local)) - :navigate? navigate? - :on-edit on-edit - :on-menu-close on-menu-close - :origin origin - :dashboard-local dashboard-local - :parent-id (str file-id "-action-menu")}])]]]]]))) + [:div {:class (stl/css-case :project-th-actions true :force-display (:menu-open @local))} + [:div + {:class (stl/css :project-th-icon :menu) + :tab-index "0" + :ref menu-ref + :id (str file-id "-action-menu") + :on-click on-menu-click + :on-key-down (fn [event] + (when (kbd/enter? event) + (dom/stop-propagation event) + (on-menu-click event)))} + i/actions + (when selected? + [:& file-menu {:files (vals selected-files) + :show? (:menu-open @local) + :left (+ 24 (:x (:menu-pos @local))) + :top (:y (:menu-pos @local)) + :navigate? navigate? + :on-edit on-edit + :on-menu-close on-menu-close + :origin origin + :dashboard-local dashboard-local + :parent-id (str file-id "-action-menu")}])]]]]])) (mf/defc grid [{:keys [files project origin limit library-view? create-fn] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - dragging? (mf/use-state false) + (let [dragging? (mf/use-state false) project-id (:id project) node-ref (mf/use-var nil) @@ -621,109 +438,58 @@ (reset! dragging? false) (import-files (.-files (.-dataTransfer e))))))] - (if new-css-system - [:div - {:class (stl/css :dashboard-grid) - :on-drag-enter on-drag-enter - :on-drag-over on-drag-over - :on-drag-leave on-drag-leave - :on-drop on-drop - :ref node-ref} + [:div {:class (stl/css :dashboard-grid) + :on-drag-enter on-drag-enter + :on-drag-over on-drag-over + :on-drag-leave on-drag-leave + :on-drop on-drop + :ref node-ref} - (cond - (nil? files) - [:& loading-placeholder] - - (seq files) - (for [slice (partition-all limit files)] - [:ul {:class (stl/css :grid-row)} - (when @dragging? - [:li {:class (stl/css :grid-item)}]) - (for [item slice] - [:& grid-item - {:file item - :key (:id item) - :navigate? true - :origin origin - :library-view? library-view?}])]) - - :else - [:& empty-placeholder - {:limit limit - :create-fn create-fn - :origin origin}])] - - ;; OLD - [:div.dashboard-grid - {:on-drag-enter on-drag-enter - :on-drag-over on-drag-over - :on-drag-leave on-drag-leave - :on-drop on-drop - :ref node-ref} - (cond - (nil? files) - [:& loading-placeholder] - - (seq files) - [:ul.grid-row - {:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} + (cond + (nil? files) + [:& loading-placeholder] + (seq files) + (for [slice (partition-all limit files)] + [:ul {:class (stl/css :grid-row)} (when @dragging? - [:li.grid-item]) - - (for [item files] + [:li {:class (stl/css :grid-item)}]) + (for [item slice] [:& grid-item {:file item :key (:id item) :navigate? true :origin origin - :library-view? library-view?}])] + :library-view? library-view?}])]) - :else - [:& empty-placeholder - {:limit limit - :create-fn create-fn - :origin origin}])]))) + :else + [:& empty-placeholder + {:limit limit + :create-fn create-fn + :origin origin}])])) (mf/defc line-grid-row [{:keys [files selected-files dragging? limit] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - elements limit + (let [elements limit limit (if dragging? (dec limit) limit)] - (if new-css-system - [:ul - {:class (stl/css :grid-row :no-wrap) - :style {:grid-template-columns (dm/str "repeat(" elements ", 1fr)")}} + [:ul + {:class (stl/css :grid-row :no-wrap) + :style {:grid-template-columns (dm/str "repeat(" elements ", 1fr)")}} - (when dragging? - [:li {:class (stl/css :grid-item :dragged)}]) + (when dragging? + [:li {:class (stl/css :grid-item :dragged)}]) - (for [item (take limit files)] - [:& grid-item - {:id (:id item) - :file item - :selected-files selected-files - :key (:id item) - :navigate? false}])] - - ;; OLD - [:ul.grid-row.no-wrap - {:style {:grid-template-columns (dm/str "repeat(" elements ", 1fr)")}} - - (when dragging? - [:li.grid-item.dragged]) - (for [item (take limit files)] - [:& grid-item - {:id (:id item) - :file item - :selected-files selected-files - :key (:id item) - :navigate? false}])]))) + (for [item (take limit files)] + [:& grid-item + {:id (:id item) + :file item + :selected-files selected-files + :key (:id item) + :navigate? false}])])) (mf/defc line-grid [{:keys [project team files limit create-fn] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - dragging? (mf/use-state false) + (let [dragging? (mf/use-state false) project-id (:id project) team-id (:id team) @@ -799,47 +565,24 @@ (reset! dragging? false) (import-files (.-files (.-dataTransfer e)))))))] - (if new-css-system - [:div {:class (stl/css :dashboard-grid) - :on-drag-enter on-drag-enter - :on-drag-over on-drag-over - :on-drag-leave on-drag-leave - :on-drop on-drop} - (cond - (nil? files) - [:& loading-placeholder] + [:div {:class (stl/css :dashboard-grid) + :on-drag-enter on-drag-enter + :on-drag-over on-drag-over + :on-drag-leave on-drag-leave + :on-drop on-drop} + (cond + (nil? files) + [:& loading-placeholder] - (seq files) - [:& line-grid-row {:files files - :team-id team-id - :selected-files selected-files - :dragging? @dragging? - :limit limit}] + (seq files) + [:& line-grid-row {:files files + :team-id team-id + :selected-files selected-files + :dragging? @dragging? + :limit limit}] - :else - [:& empty-placeholder - {:dragging? @dragging? - :limit limit - :create-fn create-fn}])] - - ;; OLD - [:div.dashboard-grid {:on-drag-enter on-drag-enter - :on-drag-over on-drag-over - :on-drag-leave on-drag-leave - :on-drop on-drop} - (cond - (nil? files) - [:& loading-placeholder] - - (seq files) - [:& line-grid-row {:files files - :team-id team-id - :selected-files selected-files - :dragging? @dragging? - :limit limit}] - - :else - [:& empty-placeholder - {:dragging? @dragging? - :limit limit - :create-fn create-fn}])]))) + :else + [:& empty-placeholder + {:dragging? @dragging? + :limit limit + :create-fn create-fn}])])) diff --git a/frontend/src/app/main/ui/dashboard/inline_edition.cljs b/frontend/src/app/main/ui/dashboard/inline_edition.cljs index 00d269066d..499f522143 100644 --- a/frontend/src/app/main/ui/dashboard/inline_edition.cljs +++ b/frontend/src/app/main/ui/dashboard/inline_edition.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.dashboard.inline-edition (:require-macros [app.main.style :as stl]) (:require - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.keyboard :as kbd] @@ -15,8 +14,7 @@ (mf/defc inline-edition [{:keys [content on-end] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - name (mf/use-state content) + (let [name (mf/use-state content) input-ref (mf/use-ref) on-input @@ -62,25 +60,14 @@ (dom/focus! node) (dom/select-text! node)))) - (if new-css-system - [:div {:class (stl/css :edit-wrapper)} - [:input {:class (stl/css :element-title) - :value @name - :ref input-ref - :on-click on-click - :on-change on-input - :on-key-down on-keyup - :on-blur on-blur}] - [:span {:class (stl/css :close) - :on-click on-cancel} i/close]] - - ;; OLD - [:div.edit-wrapper - [:input.element-title {:value @name - :ref input-ref - :on-click on-click - :on-change on-input - :on-key-down on-keyup - :on-blur on-blur}] - [:span.close {:on-click on-cancel} i/close]]))) + [:div {:class (stl/css :edit-wrapper)} + [:input {:class (stl/css :element-title) + :value @name + :ref input-ref + :on-click on-click + :on-change on-input + :on-key-down on-keyup + :on-blur on-blur}] + [:span {:class (stl/css :close) + :on-click on-cancel} i/close-refactor]])) diff --git a/frontend/src/app/main/ui/dashboard/inline_edition.scss b/frontend/src/app/main/ui/dashboard/inline_edition.scss index 8abb170cb0..0c84951f9c 100644 --- a/frontend/src/app/main/ui/dashboard/inline_edition.scss +++ b/frontend/src/app/main/ui/dashboard/inline_edition.scss @@ -12,42 +12,42 @@ padding-right: $s-24; position: relative; margin-right: $s-24; +} - input.element-title { - background-color: $db-primary; - border-radius: $br-8; - color: $df-primary; - font-size: $fs-16; - height: $s-32; - margin: 0; - border: none; - padding: $s-6; - width: 100%; +input.element-title { + background-color: $db-primary; + border-radius: $br-8; + color: $df-primary; + font-size: $fs-16; + height: $s-32; + margin: 0; + border: none; + padding: $s-6; + width: 100%; - &:focus-visible { - border: $s-1 solid $da-primary; - outline: none; - } + &:focus-visible { + border: $s-1 solid $da-primary; + outline: none; } +} - .close { - cursor: pointer; - position: absolute; +.close { + cursor: pointer; + position: absolute; - top: $s-1; - right: calc(-1 * $s-8); + top: $s-1; + right: calc(-1 * $s-8); + svg { + fill: $df-secondary; + height: $s-16; + transform: rotate(45deg) translateY(7px); + width: $s-16; + margin: 0; + } + &:hover { svg { - fill: $df-secondary; - height: $s-16; - transform: rotate(45deg) translateY(7px); - width: $s-16; - margin: 0; - } - &:hover { - svg { - fill: var(--warning-color); - } + fill: var(--warning-color); } } } diff --git a/frontend/src/app/main/ui/dashboard/libraries.cljs b/frontend/src/app/main/ui/dashboard/libraries.cljs index 2b80c8439b..dd543c154e 100644 --- a/frontend/src/app/main/ui/dashboard/libraries.cljs +++ b/frontend/src/app/main/ui/dashboard/libraries.cljs @@ -12,7 +12,6 @@ [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.grid :refer [grid]] [app.main.ui.hooks :as hooks] [app.util.dom :as dom] @@ -21,8 +20,7 @@ (mf/defc libraries-page [{:keys [team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - files-map (mf/deref refs/dashboard-shared-files) + (let [files-map (mf/deref refs/dashboard-shared-files) projects (mf/deref refs/dashboard-projects) default-project (->> projects vals (d/seek :is-default)) @@ -49,27 +47,14 @@ (st/emit! (dd/fetch-shared-files (:id team)) (dd/clear-selected-files))) - (if new-css-system - [:* - [:header {:class (stl/css :dashboard-header)} - [:div#dashboard-libraries-title {:class (stl/css :dashboard-title)} - [:h1 (tr "dashboard.libraries-title")]]] - [:section {:class (stl/css :dashboard-container :no-bg :dashboard-shared) :ref rowref} - [:& grid {:files files - :project default-project - :origin :libraries - :limit limit - :library-view? components-v2}]]] - - ;; OLD - [:* - [:header.dashboard-header {:ref rowref} - [:div.dashboard-title#dashboard-libraries-title - [:h1 (tr "dashboard.libraries-title")]]] - [:section.dashboard-container.no-bg.dashboard-shared - [:& grid {:files files - :project default-project - :origin :libraries - :limit limit - :library-view? components-v2}]]]))) + [:* + [:header {:class (stl/css :dashboard-header)} + [:div#dashboard-libraries-title {:class (stl/css :dashboard-title)} + [:h1 (tr "dashboard.libraries-title")]]] + [:section {:class (stl/css :dashboard-container :no-bg :dashboard-shared) :ref rowref} + [:& grid {:files files + :project default-project + :origin :libraries + :limit limit + :library-view? components-v2}]]])) diff --git a/frontend/src/app/main/ui/dashboard/placeholder.cljs b/frontend/src/app/main/ui/dashboard/placeholder.cljs index 37fd949f35..ce8c5d81f3 100644 --- a/frontend/src/app/main/ui/dashboard/placeholder.cljs +++ b/frontend/src/app/main/ui/dashboard/placeholder.cljs @@ -7,65 +7,39 @@ (ns app.main.ui.dashboard.placeholder (:require-macros [app.main.style :as stl]) (:require - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) (mf/defc empty-placeholder [{:keys [dragging? limit origin create-fn] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-click + (let [on-click (mf/use-fn (mf/deps create-fn) (fn [_] (create-fn "dashboard:empty-folder-placeholder")))] - (if new-css-system - (cond - (true? dragging?) - [:ul - {:class (stl/css :grid-row :no-wrap) - :style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} - [:li {:class (stl/css :grid-item :grid-empty-placeholder :dragged)}]] + (cond + (true? dragging?) + [:ul + {:class (stl/css :grid-row :no-wrap) + :style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} + [:li {:class (stl/css :grid-item :grid-empty-placeholder :dragged)}]] - (= :libraries origin) - [:div {:class (stl/css :grid-empty-placeholder :libs) - :data-test "empty-placeholder"} - [:div {:class (stl/css :text)} - [:& i18n/tr-html {:label "dashboard.empty-placeholder-drafts"}]]] + (= :libraries origin) + [:div {:class (stl/css :grid-empty-placeholder :libs) + :data-test "empty-placeholder"} + [:div {:class (stl/css :text)} + [:& i18n/tr-html {:label "dashboard.empty-placeholder-drafts"}]]] - :else - [:div - {:class (stl/css :grid-empty-placeholder)} - [:button {:class (stl/css :create-new) - :on-click on-click} - i/add-refactor]]) - - ;; OLD - (cond - (true? dragging?) - [:ul.grid-row.no-wrap - {:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} - [:li.grid-item]] - - (= :libraries origin) - [:div.grid-empty-placeholder.libs {:data-test "empty-placeholder"} - [:div.text - [:& i18n/tr-html {:label "dashboard.empty-placeholder-drafts"}]]] - - :else - [:div.grid-empty-placeholder - {:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} - [:button.create-new {:on-click on-click} (tr "dashboard.new-file")]])))) + :else + [:div + {:class (stl/css :grid-empty-placeholder)} + [:button {:class (stl/css :create-new) + :on-click on-click} + i/add-refactor]]))) (mf/defc loading-placeholder [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :grid-empty-placeholder :loader)} - [:div {:class (stl/css :icon)} i/loader] - [:div {:class (stl/css :text)} (tr "dashboard.loading-files")]] - - [:div.grid-empty-placeholder.loader - [:div.icon i/loader] - [:div.text (tr "dashboard.loading-files")]]))) + [:div {:class (stl/css :grid-empty-placeholder :loader)} + [:div {:class (stl/css :icon)} i/loader] + [:div {:class (stl/css :text)} (tr "dashboard.loading-files")]]) diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index 572c72f778..035385bb49 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -18,7 +18,6 @@ [app.main.errors :as errors] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.grid :refer [line-grid]] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] [app.main.ui.dashboard.project-menu :refer [project-menu]] @@ -37,32 +36,20 @@ (mf/defc header {::mf/wrap [mf/memo]} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-click (mf/use-fn #(st/emit! (dd/create-project)))] - (if new-css-system - [:header {:class (stl/css :dashboard-header)} - [:div#dashboard-projects-title {:class (stl/css :dashboard-title)} - [:h1 (tr "dashboard.projects-title")]] - [:button - {:class (stl/css :btn-secondary :btn-small) - :on-click on-click - :data-test "new-project-button"} - (tr "dashboard.new-project")]] - - ;; OLD - [:header.dashboard-header - [:div.dashboard-title#dashboard-projects-title - [:h1 (tr "dashboard.projects-title")]] - [:button.btn-secondary.btn-small - {:on-click on-click - :data-test "new-project-button"} - (tr "dashboard.new-project")]]))) + (let [on-click (mf/use-fn #(st/emit! (dd/create-project)))] + [:header {:class (stl/css :dashboard-header)} + [:div#dashboard-projects-title {:class (stl/css :dashboard-title)} + [:h1 (tr "dashboard.projects-title")]] + [:button + {:class (stl/css :btn-secondary :btn-small) + :on-click on-click + :data-test "new-project-button"} + (tr "dashboard.new-project")]])) (mf/defc team-hero {::mf/wrap [mf/memo]} [{:keys [team close-fn] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-nav-members-click (mf/use-fn #(st/emit! (dd/go-to-team-members))) + (let [on-nav-members-click (mf/use-fn #(st/emit! (dd/go-to-team-members))) on-invite-click (mf/use-fn @@ -78,52 +65,33 @@ (dom/prevent-default event) (close-fn)))] - (if new-css-system - [:div {:class (stl/css :team-hero)} - [:div {:class (stl/css :img-wrapper)} - [:img {:src "images/deco-team-banner.png" - :border "0" - :role "presentation"}]] - [:div {:class (stl/css :text)} - [:div {:class (stl/css :title)} (tr "dasboard.team-hero.title")] - [:div {:class (stl/css :info)} - [:span (tr "dasboard.team-hero.text")] - [:a {:on-click on-nav-members-click} (tr "dasboard.team-hero.management")]] - [:button - {:class (stl/css :btn-primary :invite) - :on-click on-invite-click} - (tr "onboarding.choice.team-up.invite-members")]] + [:div {:class (stl/css :team-hero)} + [:div {:class (stl/css :img-wrapper)} + [:img {:src "images/deco-team-banner.png" + :border "0" + :role "presentation"}]] + [:div {:class (stl/css :text)} + [:div {:class (stl/css :title)} (tr "dasboard.team-hero.title")] + [:div {:class (stl/css :info)} + [:span (tr "dasboard.team-hero.text")] + [:a {:on-click on-nav-members-click} (tr "dasboard.team-hero.management")]] + [:button + {:class (stl/css :btn-primary :invite) + :on-click on-invite-click} + (tr "onboarding.choice.team-up.invite-members")]] - [:button - {:class (stl/css :close) - :on-click on-close-click - :aria-label (tr "labels.close")} - [:span i/close]]] - - ;; OLD - [:div.team-hero - [:img {:src "images/deco-team-banner.png" :border "0" - :role "presentation"}] - [:div.text - [:div.title (tr "dasboard.team-hero.title")] - [:div.info - [:span (tr "dasboard.team-hero.text")] - [:a {:on-click on-nav-members-click} (tr "dasboard.team-hero.management")]]] - [:button.btn-primary.invite - {:on-click on-invite-click} - (tr "onboarding.choice.team-up.invite-members")] - [:button.close - {:on-click on-close-click - :aria-label (tr "labels.close")} - [:span i/close]]]))) + [:button + {:class (stl/css :close) + :on-click on-close-click + :aria-label (tr "labels.close")} + [:span i/close]]])) (def builtin-templates (l/derived :builtin-templates st/state)) (mf/defc tutorial-project [{:keys [close-tutorial default-project-id] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - state (mf/use-state {:status :waiting + (let [state (mf/use-state {:status :waiting :file nil}) templates (mf/deref builtin-templates) @@ -155,88 +123,51 @@ (swap! state #(assoc % :status :importing)) (st/emit! (with-meta (dd/clone-template (with-meta params mdata)) {::ev/origin "get-started-hero-block"})))))] - (if new-css-system - [:article {:class (stl/css :tutorial)} - [:div {:class (stl/css :thumbnail)}] - [:div {:class (stl/css :text)} - [:h2 {:class (stl/css :title)} (tr "dasboard.tutorial-hero.title")] - [:p {:class (stl/css :info)} (tr "dasboard.tutorial-hero.info")] - [:button {:class (stl/css :btn-primary :action) - :on-click download-tutorial} - (case (:status @state) - :waiting (tr "dasboard.tutorial-hero.start") - :importing [:span.loader i/loader-pencil] - :success "")]] + [:article {:class (stl/css :tutorial)} + [:div {:class (stl/css :thumbnail)}] + [:div {:class (stl/css :text)} + [:h2 {:class (stl/css :title)} (tr "dasboard.tutorial-hero.title")] + [:p {:class (stl/css :info)} (tr "dasboard.tutorial-hero.info")] + [:button {:class (stl/css :btn-primary :action) + :on-click download-tutorial} + (case (:status @state) + :waiting (tr "dasboard.tutorial-hero.start") + :importing [:span.loader i/loader-pencil] + :success "")]] - [:button - {:class (stl/css :close) - :on-click close-tutorial - :aria-label (tr "labels.close")} - [:span {:class (stl/css :icon)} i/close]]] - - ;; OLD - [:article.tutorial - [:div.thumbnail] - [:div.text - [:h2.title (tr "dasboard.tutorial-hero.title")] - [:p.info (tr "dasboard.tutorial-hero.info")] - [:button.btn-primary.action {:on-click download-tutorial} - (case (:status @state) - :waiting (tr "dasboard.tutorial-hero.start") - :importing [:span.loader i/loader-pencil] - :success "")]] - - [:button.close - {:on-click close-tutorial - :aria-label (tr "labels.close")} - [:span.icon i/close]]]))) + [:button + {:class (stl/css :close) + :on-click close-tutorial + :aria-label (tr "labels.close")} + [:span {:class (stl/css :icon)} i/close]]])) (mf/defc interface-walkthrough {::mf/wrap [mf/memo]} [{:keys [close-walkthrough] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - handle-walkthrough-link + (let [handle-walkthrough-link (fn [] (st/emit! (ptk/event ::ev/event {::ev/name "show-walkthrough" ::ev/origin "get-started-hero-block" :section "dashboard"})))] - (if new-css-system - [:article {:class (stl/css :walkthrough)} - [:div {:class (stl/css :thumbnail)}] - [:div {:class (stl/css :text)} - [:h2 {:class (stl/css :title)} (tr "dasboard.walkthrough-hero.title")] - [:p {:class (stl/css :info)} (tr "dasboard.walkthrough-hero.info")] - [:a {:class (stl/css :btn-primary :action) - :href " https://design.penpot.app/walkthrough" - :target "_blank" - :on-click handle-walkthrough-link} - (tr "dasboard.walkthrough-hero.start")]] - [:button - {:class (stl/css :close) - :on-click close-walkthrough - :aria-label (tr "labels.close")} - [:span {:class (stl/css :icon)} i/close]]] - - ;; OLD - [:article.walkthrough - [:div.thumbnail] - [:div.text - [:h2.title (tr "dasboard.walkthrough-hero.title")] - [:p.info (tr "dasboard.walkthrough-hero.info")] - [:a.btn-primary.action - {:href " https://design.penpot.app/walkthrough" - :target "_blank" - :on-click handle-walkthrough-link} - (tr "dasboard.walkthrough-hero.start")]] - [:button.close - {:on-click close-walkthrough - :aria-label (tr "labels.close")} - [:span.icon i/close]]]))) + [:article {:class (stl/css :walkthrough)} + [:div {:class (stl/css :thumbnail)}] + [:div {:class (stl/css :text)} + [:h2 {:class (stl/css :title)} (tr "dasboard.walkthrough-hero.title")] + [:p {:class (stl/css :info)} (tr "dasboard.walkthrough-hero.info")] + [:a {:class (stl/css :btn-primary :action) + :href " https://design.penpot.app/walkthrough" + :target "_blank" + :on-click handle-walkthrough-link} + (tr "dasboard.walkthrough-hero.start")]] + [:button + {:class (stl/css :close) + :on-click close-walkthrough + :aria-label (tr "labels.close")} + [:span {:class (stl/css :icon)} i/close]]])) (mf/defc project-item [{:keys [project first? team files] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - locale (mf/deref i18n/locale) + (let [locale (mf/deref i18n/locale) file-count (or (:count project) 0) project-id (:id project) team-id (:id team) @@ -344,166 +275,85 @@ (dom/stop-propagation event) (on-menu-click event))))] - (if new-css-system - [:article {:class (stl/css-case :dashboard-project-row true :first first?)} - [:header {:class (stl/css :project)} - [:div {:class (stl/css :project-name-wrapper)} - (if (:edition? @local) - [:& inline-edition {:content (:name project) - :on-end on-edit}] - [:h2 {:on-click on-nav - :on-context-menu on-menu-click} - (if (:is-default project) - (tr "labels.drafts") - (:name project))]) + [:article {:class (stl/css-case :dashboard-project-row true :first first?)} + [:header {:class (stl/css :project)} + [:div {:class (stl/css :project-name-wrapper)} + (if (:edition? @local) + [:& inline-edition {:content (:name project) + :on-end on-edit}] + [:h2 {:on-click on-nav + :on-context-menu on-menu-click} + (if (:is-default project) + (tr "labels.drafts") + (:name project))]) - [:& project-menu - {:project project - :show? (:menu-open @local) - :left (+ 24 (:x (:menu-pos @local))) - :top (:y (:menu-pos @local)) - :on-edit on-edit-open - :on-menu-close on-menu-close - :on-import on-import}] - - [:span {:class (stl/css :info)} (str (tr "labels.num-of-files" (i18n/c file-count)))] - - (let [time (-> (:modified-at project) - (dt/timeago {:locale locale}))] - [:span {:class (stl/css :recent-files-row-title-info)} (str ", " time)]) - - [:div {:class (stl/css :project-actions)} - (when-not (:is-default project) - [:button - {:class (stl/css-case :pin-icon true - :tooltip true - :tooltip-bottom true - :active (:is-pinned project)) - :on-click toggle-pin - :alt (tr "dashboard.pin-unpin") - :aria-label (tr "dashboard.pin-unpin") - :tab-index "0"} - (if (:is-pinned project) - i/pin-fill - i/pin)]) - - [:button - {:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom) - :on-click on-create-click - :alt (tr "dashboard.new-file") - :aria-label (tr "dashboard.new-file") - :data-test "project-new-file" - :on-key-down handle-create-click} - i/close] - - [:button - {:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom) - :on-click on-menu-click - :alt (tr "dashboard.options") - :aria-label (tr "dashboard.options") - :data-test "project-options" - :on-key-down handle-menu-click} - i/actions]]]] - - [:div {:class (stl/css :grid-container) :ref rowref} - [:& line-grid - {:project project - :team team - :files files - :create-fn create-file - :limit limit}]] - - (when (and (> limit 0) - (> file-count limit)) - [:button - {:class (stl/css :show-more) - :on-click on-nav - :tab-index "0" - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-nav)))} - [:div {:class (stl/css :placeholder-label)} (tr "dashboard.show-all-files")] - [:div {:class (stl/css :placeholder-icon)} i/arrow-down]])] - - ;; OLD - [:article.dashboard-project-row - {:class (when first? "first")} - [:header.project {:ref rowref} - [:div.project-name-wrapper - (if (:edition? @local) - [:& inline-edition {:content (:name project) - :on-end on-edit}] - [:h2 {:on-click on-nav - :on-context-menu on-menu-click} - (if (:is-default project) - (tr "labels.drafts") - (:name project))]) - - [:& project-menu - {:project project - :show? (:menu-open @local) - :left (+ 24 (:x (:menu-pos @local))) - :top (:y (:menu-pos @local)) - :on-edit on-edit-open - :on-menu-close on-menu-close - :on-import on-import}] - - [:span.info (str (tr "labels.num-of-files" (i18n/c file-count)))] - (let [time (-> (:modified-at project) - (dt/timeago {:locale locale}))] - [:span.recent-files-row-title-info (str ", " time)]) - [:div.project-actions - (when-not (:is-default project) - [:button.pin-icon.tooltip.tooltip-bottom - {:class (when (:is-pinned project) "active") - :on-click toggle-pin - :alt (tr "dashboard.pin-unpin") - :aria-label (tr "dashboard.pin-unpin") - :tab-index "0"} - (if (:is-pinned project) - i/pin-fill - i/pin)]) - - [:button.btn-secondary.btn-small.tooltip.tooltip-bottom - {:on-click on-create-click - :alt (tr "dashboard.new-file") - :aria-label (tr "dashboard.new-file") - :data-test "project-new-file" - :tab-index "0" - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-create-click event)))} - i/close] - - [:button.btn-secondary.btn-small.tooltip.tooltip-bottom - {:on-click on-menu-click - :alt (tr "dashboard.options") - :aria-label (tr "dashboard.options") - :data-test "project-options" - :tab-index "0" - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/stop-propagation event) - (on-menu-click event)))} - i/actions]]]] - - [:& line-grid + [:& project-menu {:project project - :team team - :files files - :create-fn create-file - :limit limit}] + :show? (:menu-open @local) + :left (+ 24 (:x (:menu-pos @local))) + :top (:y (:menu-pos @local)) + :on-edit on-edit-open + :on-menu-close on-menu-close + :on-import on-import}] - (when (and (> limit 0) - (> file-count limit)) - [:button.show-more {:on-click on-nav - :tab-index "0" - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-nav)))} - [:div.placeholder-label - (tr "dashboard.show-all-files")] - [:div.placeholder-icon i/arrow-down]])]))) + [:span {:class (stl/css :info)} (str (tr "labels.num-of-files" (i18n/c file-count)))] + + (let [time (-> (:modified-at project) + (dt/timeago {:locale locale}))] + [:span {:class (stl/css :recent-files-row-title-info)} (str ", " time)]) + + [:div {:class (stl/css :project-actions)} + (when-not (:is-default project) + [:button + {:class (stl/css-case :pin-icon true + :tooltip true + :tooltip-bottom true + :active (:is-pinned project)) + :on-click toggle-pin + :alt (tr "dashboard.pin-unpin") + :aria-label (tr "dashboard.pin-unpin") + :tab-index "0"} + (if (:is-pinned project) + i/pin-fill + i/pin)]) + + [:button + {:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom) + :on-click on-create-click + :alt (tr "dashboard.new-file") + :aria-label (tr "dashboard.new-file") + :data-test "project-new-file" + :on-key-down handle-create-click} + i/close] + + [:button + {:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom) + :on-click on-menu-click + :alt (tr "dashboard.options") + :aria-label (tr "dashboard.options") + :data-test "project-options" + :on-key-down handle-menu-click} + i/actions]]]] + + [:div {:class (stl/css :grid-container) :ref rowref} + [:& line-grid + {:project project + :team team + :files files + :create-fn create-file + :limit limit}]] + + (when (and (> limit 0) + (> file-count limit)) + [:button + {:class (stl/css :show-more) + :on-click on-nav + :tab-index "0" + :on-key-down (fn [event] + (when (kbd/enter? event) + (on-nav)))} + [:div {:class (stl/css :placeholder-label)} (tr "dashboard.show-all-files")] + [:div {:class (stl/css :placeholder-icon)} i/arrow-down]])])) (def recent-files-ref @@ -511,8 +361,7 @@ (mf/defc projects-section [{:keys [team projects profile default-project-id] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - projects (->> (vals projects) + (let [projects (->> (vals projects) (sort-by :modified-at) (reverse)) recent-map (mf/deref recent-files-ref) @@ -562,68 +411,34 @@ (st/emit! (dd/fetch-recent-files team-id) (dd/clear-selected-files))) - (if new-css-system - (when (seq projects) - [:* - [:& header] + (when (seq projects) + [:* + [:& header] - (when team-hero? - [:& team-hero {:team team :close-fn close-banner}]) + (when team-hero? + [:& team-hero {:team team :close-fn close-banner}]) - (when (and (contains? cf/flags :dashboard-templates-section) - (or (not tutorial-viewed?) - (not walkthrough-viewed?))) - [:div {:class (stl/css :hero-projects)} - (when (and (not tutorial-viewed?) (:is-default team)) - [:& tutorial-project - {:close-tutorial close-tutorial - :default-project-id default-project-id}]) + (when (and (contains? cf/flags :dashboard-templates-section) + (or (not tutorial-viewed?) + (not walkthrough-viewed?))) + [:div {:class (stl/css :hero-projects)} + (when (and (not tutorial-viewed?) (:is-default team)) + [:& tutorial-project + {:close-tutorial close-tutorial + :default-project-id default-project-id}]) - (when (and (not walkthrough-viewed?) (:is-default team)) - [:& interface-walkthrough - {:close-walkthrough close-walkthrough}])]) + (when (and (not walkthrough-viewed?) (:is-default team)) + [:& interface-walkthrough + {:close-walkthrough close-walkthrough}])]) - [:div {:class (stl/css :dashboard-container :no-bg :dashboard-projects)} - (for [{:keys [id] :as project} projects] - (let [files (when recent-map - (->> (vals recent-map) - (filterv #(= id (:project-id %))) - (sort-by :modified-at #(compare %2 %1))))] - [:& project-item {:project project - :team team - :files files - :first? (= project (first projects)) - :key id}]))]]) - - ;; OLD - (when (seq projects) - [:* - [:& header] - - (when team-hero? - [:& team-hero {:team team :close-fn close-banner}]) - - (when (and (contains? cf/flags :dashboard-templates-section) - (or (not tutorial-viewed?) - (not walkthrough-viewed?))) - [:div.hero-projects - (when (and (not tutorial-viewed?) (:is-default team)) - [:& tutorial-project - {:close-tutorial close-tutorial - :default-project-id default-project-id}]) - - (when (and (not walkthrough-viewed?) (:is-default team)) - [:& interface-walkthrough - {:close-walkthrough close-walkthrough}])]) - - [:div.dashboard-container.no-bg.dashboard-projects - (for [{:keys [id] :as project} projects] - (let [files (when recent-map - (->> (vals recent-map) - (filterv #(= id (:project-id %))) - (sort-by :modified-at #(compare %2 %1))))] - [:& project-item {:project project - :team team - :files files - :first? (= project (first projects)) - :key id}]))]])))) + [:div {:class (stl/css :dashboard-container :no-bg :dashboard-projects)} + (for [{:keys [id] :as project} projects] + (let [files (when recent-map + (->> (vals recent-map) + (filterv #(= id (:project-id %))) + (sort-by :modified-at #(compare %2 %1))))] + [:& project-item {:project project + :team team + :files files + :first? (= project (first projects)) + :key id}]))]]))) diff --git a/frontend/src/app/main/ui/dashboard/search.cljs b/frontend/src/app/main/ui/dashboard/search.cljs index 1f47edb4ed..3b4d090996 100644 --- a/frontend/src/app/main/ui/dashboard/search.cljs +++ b/frontend/src/app/main/ui/dashboard/search.cljs @@ -10,7 +10,6 @@ [app.main.data.dashboard :as dd] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.grid :refer [grid]] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] @@ -20,8 +19,7 @@ (mf/defc search-page [{:keys [team search-term] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - result (mf/deref refs/dashboard-search-result) + (let [result (mf/deref refs/dashboard-search-result) [rowref limit] (hooks/use-dynamic-grid-item-width)] (mf/use-effect @@ -38,61 +36,31 @@ (fn [] (st/emit! (dd/search {:search-term search-term}) (dd/clear-selected-files)))) - (if new-css-system - [:* - [:header {:class (stl/css :dashboard-header)} - [:div#dashboard-search-title {:class (stl/css :dashboard-title)} - [:h1 (tr "dashboard.title-search")]]] + [:* + [:header {:class (stl/css :dashboard-header)} + [:div#dashboard-search-title {:class (stl/css :dashboard-title)} + [:h1 (tr "dashboard.title-search")]]] - [:section {:class (stl/css :dashboard-container :search :no-bg) - :ref rowref} - (cond - (empty? search-term) - [:div {:class (stl/css :grid-empty-placeholder :search)} - [:div {:class (stl/css :icon)} i/search] - [:div {:class (stl/css :text)} (tr "dashboard.type-something")]] + [:section {:class (stl/css :dashboard-container :search :no-bg) + :ref rowref} + (cond + (empty? search-term) + [:div {:class (stl/css :grid-empty-placeholder :search)} + [:div {:class (stl/css :icon)} i/search] + [:div {:class (stl/css :text)} (tr "dashboard.type-something")]] - (nil? result) - [:div {:class (stl/css :grid-empty-placeholder :search)} - [:div {:class (stl/css :icon)} i/search] - [:div {:class (stl/css :text)} (tr "dashboard.searching-for" search-term)]] + (nil? result) + [:div {:class (stl/css :grid-empty-placeholder :search)} + [:div {:class (stl/css :icon)} i/search] + [:div {:class (stl/css :text)} (tr "dashboard.searching-for" search-term)]] - (empty? result) - [:div {:class (stl/css :grid-empty-placeholder :search)} - [:div {:class (stl/css :icon)} i/search] - [:div {:class (stl/css :text)} (tr "dashboard.no-matches-for" search-term)]] + (empty? result) + [:div {:class (stl/css :grid-empty-placeholder :search)} + [:div {:class (stl/css :icon)} i/search] + [:div {:class (stl/css :text)} (tr "dashboard.no-matches-for" search-term)]] - :else - [:& grid {:files result - :hide-new? true - :origin :search - :limit limit}])]] - - ;; OLD - [:* - [:header.dashboard-header - [:div.dashboard-title#dashboard-search-title - [:h1 (tr "dashboard.title-search")]]] - - [:section.dashboard-container.search.no-bg {:ref rowref} - (cond - (empty? search-term) - [:div.grid-empty-placeholder.search - [:div.icon i/search] - [:div.text (tr "dashboard.type-something")]] - - (nil? result) - [:div.grid-empty-placeholder.search - [:div.icon i/search] - [:div.text (tr "dashboard.searching-for" search-term)]] - - (empty? result) - [:div.grid-empty-placeholder.search - [:div.icon i/search] - [:div.text (tr "dashboard.no-matches-for" search-term)]] - - :else - [:& grid {:files result - :hide-new? true - :origin :search - :limit limit}])]]))) + :else + [:& grid {:files result + :hide-new? true + :origin :search + :limit limit}])]])) diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 4b61fb2bab..219883e931 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -20,7 +20,6 @@ [app.main.store :as st] [app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]] [app.main.ui.components.link :refer [link]] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.comments :refer [comments-icon comments-section]] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] [app.main.ui.dashboard.project-menu :refer [project-menu]] @@ -41,8 +40,7 @@ (mf/defc sidebar-project [{:keys [item selected?] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - dstate (mf/deref refs/dashboard-local) + (let [dstate (mf/deref refs/dashboard-local) selected-files (:selected-files dstate) selected-project (:selected-project dstate) edit-id (:project-for-edit dstate) @@ -136,59 +134,33 @@ mdata {:on-success on-drop-success}] (st/emit! (dd/move-files (with-meta data mdata)))))))] - (if new-css-system - [:* - [:li {:tab-index "0" - :class (stl/css-case :project-element true - :current selected? - :dragging (:dragging? local)) - :on-click on-click - :on-key-down on-key-down - :on-double-click on-edit-open - :on-context-menu on-menu-click - :on-drag-enter on-drag-enter - :on-drag-over on-drag-over - :on-drag-leave on-drag-leave - :on-drop on-drop} - (if (:edition? local) - [:& inline-edition {:content (:name item) - :on-end on-edit}] - [:span {:class (stl/css :element-title)} (:name item)])] - [:& project-menu {:project item - :show? (:menu-open local) - :left (:x (:menu-pos local)) - :top (:y (:menu-pos local)) - :on-edit on-edit-open - :on-menu-close on-menu-close}]] - - ;; OLD - [:* - [:li {:tab-index "0" - :class (if selected? "current" - (when (:dragging? local) "dragging")) - :on-click on-click - :on-key-down on-key-down - :on-double-click on-edit-open - :on-context-menu on-menu-click - :on-drag-enter on-drag-enter - :on-drag-over on-drag-over - :on-drag-leave on-drag-leave - :on-drop on-drop} - (if (:edition? local) - [:& inline-edition {:content (:name item) - :on-end on-edit}] - [:span.element-title (:name item)])] - [:& project-menu {:project item - :show? (:menu-open local) - :left (:x (:menu-pos local)) - :top (:y (:menu-pos local)) - :on-edit on-edit-open - :on-menu-close on-menu-close}]]))) + [:* + [:li {:tab-index "0" + :class (stl/css-case :project-element true + :current selected? + :dragging (:dragging? local)) + :on-click on-click + :on-key-down on-key-down + :on-double-click on-edit-open + :on-context-menu on-menu-click + :on-drag-enter on-drag-enter + :on-drag-over on-drag-over + :on-drag-leave on-drag-leave + :on-drop on-drop} + (if (:edition? local) + [:& inline-edition {:content (:name item) + :on-end on-edit}] + [:span {:class (stl/css :element-title)} (:name item)])] + [:& project-menu {:project item + :show? (:menu-open local) + :left (:x (:menu-pos local)) + :top (:y (:menu-pos local)) + :on-edit on-edit-open + :on-menu-close on-menu-close}]])) (mf/defc sidebar-search [{:keys [search-term team-id] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - search-term (or search-term "") + (let [search-term (or search-term "") focused? (mf/use-state false) emit! (mf/use-memo #(f/debounce st/emit! 500)) @@ -236,70 +208,39 @@ (when (kbd/enter? event) (on-clear-click event))))] - (if new-css-system - [:form {:class (stl/css :sidebar-search)} - [:input - {:class (stl/css :input-text) - :key "images-search-box" - :id "search-input" - :type "text" - :aria-label (tr "dashboard.search-placeholder") - :placeholder (tr "dashboard.search-placeholder") - :default-value search-term - :auto-complete "off" - ;; :on-focus on-search-focus - :on-blur on-search-blur - :on-change on-search-change - :on-key-press on-key-press - :ref #(when % (set! (.-value %) search-term))}] + [:form {:class (stl/css :sidebar-search)} + [:input + {:class (stl/css :input-text) + :key "images-search-box" + :id "search-input" + :type "text" + :aria-label (tr "dashboard.search-placeholder") + :placeholder (tr "dashboard.search-placeholder") + :default-value search-term + :auto-complete "off" + ;; :on-focus on-search-focus + :on-blur on-search-blur + :on-change on-search-change + :on-key-press on-key-press + :ref #(when % (set! (.-value %) search-term))}] - (if (or @focused? (seq search-term)) - [:div - {:class (stl/css :clear-search) - :tab-index "0" - :on-click on-clear-click - :on-key-down handle-clear-search} - i/close] + (if (or @focused? (seq search-term)) + [:div + {:class (stl/css :clear-search) + :tab-index "0" + :on-click on-clear-click + :on-key-down handle-clear-search} + i/close] - [:div - {:class (stl/css :search) - :on-click on-clear-click} - i/search])] - - ;; OLD - [:form.sidebar-search - [:input.input-text - {:key "images-search-box" - :id "search-input" - :type "text" - :aria-label (tr "dashboard.search-placeholder") - :placeholder (tr "dashboard.search-placeholder") - :default-value search-term - :auto-complete "off" - ;; :on-focus on-search-focus - :on-blur on-search-blur - :on-change on-search-change - :on-key-press on-key-press - :ref #(when % (set! (.-value %) search-term))}] - - (if (or @focused? (seq search-term)) - [:div.clear-search - {:tab-index "0" - :on-click on-clear-click - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-clear-click event)))} - i/close] - - [:div.search - {:on-click on-clear-click} - i/search])]))) + [:div + {:class (stl/css :search) + :on-click on-clear-click} + i/search])])) (mf/defc teams-selector-dropdown-items {::mf/wrap-props false} [{:keys [team profile teams] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-create-clicked + (let [on-create-clicked (mf/use-callback #(st/emit! (modal/show :team-form {}))) @@ -318,76 +259,38 @@ (when (kbd/enter? event) (team-selected id event)))] - (if new-css-system - [:* - [:> dropdown-menu-item* {:on-click (partial team-selected (:default-team-id profile)) - :on-key-down handle-select-default - :id "teams-selector-default-team" - :class (stl/css :team-name)} - [:span {:class (stl/css :team-icon)} i/logo-icon] - [:span {:class (stl/css :team-text)} (tr "dashboard.your-penpot")] - (when (= (:default-team-id profile) (:id team)) - [:span {:class (stl/css :icon)} i/tick])] + [:* + [:> dropdown-menu-item* {:on-click (partial team-selected (:default-team-id profile)) + :on-key-down handle-select-default + :id "teams-selector-default-team" + :class (stl/css :team-name)} + [:span {:class (stl/css :team-icon)} i/logo-icon] + [:span {:class (stl/css :team-text)} (tr "dashboard.your-penpot")] + (when (= (:default-team-id profile) (:id team)) + [:span {:class (stl/css :icon)} i/tick])] - (for [team-item (remove :is-default (vals teams))] - [:> dropdown-menu-item* {:on-click (partial team-selected (:id team-item)) - :on-key-down (partial handle-select-team (:id team-item)) - :id (str "teams-selector-" (:id team-item)) - :class (stl/css :team-name) - :key (str "teams-selector-" (:id team-item))} - [:span {:class (stl/css :team-icon)} - [:img {:src (cf/resolve-team-photo-url team-item) - :alt (:name team-item)}]] - [:span {:class (stl/css :team-text) - :title (:name team-item)} (:name team-item)] - (when (= (:id team-item) (:id team)) - [:span {:class (stl/css :icon)} i/tick])]) - [:hr {:role "separator"}] - [:> dropdown-menu-item* {:on-click on-create-clicked - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-create-clicked event))) - :id "teams-selector-create-team" - :class (stl/css :team-name :action)} - [:span {:class (stl/css :team-icon :new-team)} i/close] - [:span {:class (stl/css :team-text)} (tr "dashboard.create-new-team")]]] - - ;; OLD - [:* - [:> dropdown-menu-item* {:on-click (partial team-selected (:default-team-id profile)) - :on-key-down (fn [event] - (when (kbd/enter? event) - (team-selected (:default-team-id profile) event))) - :id "teams-selector-default-team" - :class "team-name"} - [:span.team-icon i/logo-icon] - [:span.team-text (tr "dashboard.your-penpot")] - (when (= (:default-team-id profile) (:id team)) - [:span.icon i/tick])] - - (for [team-item (remove :is-default (vals teams))] - [:> dropdown-menu-item* {:on-click (partial team-selected (:id team-item)) - :on-key-down (fn [event] - (when (kbd/enter? event) - (team-selected (:id team-item) event))) - :id (str "teams-selector-" (:id team-item)) - :class "team-name" - :key (str "teams-selector-" (:id team-item))} - [:span.team-icon - [:img {:src (cf/resolve-team-photo-url team-item) - :alt (:name team-item)}]] - [:span.team-text {:title (:name team-item)} (:name team-item)] - (when (= (:id team-item) (:id team)) - [:span.icon i/tick])]) - [:hr {:role "separator"}] - [:> dropdown-menu-item* {:on-click on-create-clicked - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-create-clicked event))) - :id "teams-selector-create-team" - :class "team-name action"} - [:span.team-icon.new-team i/close] - [:span.team-text (tr "dashboard.create-new-team")]]]))) + (for [team-item (remove :is-default (vals teams))] + [:> dropdown-menu-item* {:on-click (partial team-selected (:id team-item)) + :on-key-down (partial handle-select-team (:id team-item)) + :id (str "teams-selector-" (:id team-item)) + :class (stl/css :team-name) + :key (str "teams-selector-" (:id team-item))} + [:span {:class (stl/css :team-icon)} + [:img {:src (cf/resolve-team-photo-url team-item) + :alt (:name team-item)}]] + [:span {:class (stl/css :team-text) + :title (:name team-item)} (:name team-item)] + (when (= (:id team-item) (:id team)) + [:span {:class (stl/css :icon)} i/tick])]) + [:hr {:role "separator"}] + [:> dropdown-menu-item* {:on-click on-create-clicked + :on-key-down (fn [event] + (when (kbd/enter? event) + (on-create-clicked event))) + :id "teams-selector-create-team" + :class (stl/css :team-name :action)} + [:span {:class (stl/css :team-icon :new-team)} i/close] + [:span {:class (stl/css :team-text)} (tr "dashboard.create-new-team")]]])) (s/def ::member-id ::us/uuid) (s/def ::leave-modal-form @@ -395,8 +298,7 @@ (mf/defc team-options-dropdown [{:keys [team profile] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - go-members #(st/emit! (dd/go-to-team-members)) + (let [go-members #(st/emit! (dd/go-to-team-members)) go-invitations #(st/emit! (dd/go-to-team-invitations)) go-webhooks #(st/emit! (dd/go-to-team-webhooks)) go-settings #(st/emit! (dd/go-to-team-settings)) @@ -549,15 +451,13 @@ (when (kbd/enter? event) (on-delete-clicked))) :id "teams-options-delete-team" - :class (if new-css-system (stl/css :warning) "warning") + :class (stl/css :warning) :data-test "delete-team"} (tr "dashboard.delete-team")])])) - (mf/defc sidebar-team-switch [{:keys [team profile] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - teams (mf/deref refs/teams) + (let [teams (mf/deref refs/teams) teams-without-default (into {} (filter (fn [[_ v]] (= false (:is-default v))) teams)) team-ids (map #(str "teams-selector-" %) (keys teams-without-default)) ids (concat ["teams-selector-default-team"] team-ids ["teams-selector-create-team"]) @@ -615,119 +515,55 @@ (fn [] (reset! show-teams-ddwn? false))] - (if new-css-system - [:div {:class (stl/css :sidebar-team-switch)} - [:div {:class (stl/css :switch-content)} + [:div {:class (stl/css :sidebar-team-switch)} + [:div {:class (stl/css :switch-content)} + [:button + {:class (stl/css :current-team) + :tab-index "0" + :on-click handle-show-team-click + :on-key-down handle-show-team-keydown} + + + (if (:is-default team) + [:div {:class (stl/css :team-name)} + [:span {:class (stl/css :team-icon)} i/logo-icon] + [:span {:class (stl/css :team-text)} (tr "dashboard.default-team-name")]] + [:div {:class (stl/css :team-name)} + [:span {:class (stl/css :team-icon)} + [:img {:src (cf/resolve-team-photo-url team) + :alt (:name team)}]] + [:span {:class (stl/css :team-text) :title (:name team)} (:name team)]]) + + [:span {:class (stl/css :switch-icon)} i/arrow-down]] + + (when-not (:is-default team) [:button - {:class (stl/css :current-team) + {:class (stl/css :switch-options) + :on-click handle-show-opts-click :tab-index "0" - :on-click handle-show-team-click - :on-key-down handle-show-team-keydown} + :on-key-down handle-show-opts-keydown} + i/actions])] + ;; Teams Dropdown + [:& dropdown-menu {:show @show-teams-ddwn? + :on-close handle-close-team + :ids ids + :list-class (stl/css :dropdown :teams-dropdown)} + [:& teams-selector-dropdown-items {:ids ids + :team team + :profile profile + :teams teams}]] - (if (:is-default team) - [:div {:class (stl/css :team-name)} - [:span {:class (stl/css :team-icon)} i/logo-icon] - [:span {:class (stl/css :team-text)} (tr "dashboard.default-team-name")]] - [:div {:class (stl/css :team-name)} - [:span {:class (stl/css :team-icon)} - [:img {:src (cf/resolve-team-photo-url team) - :alt (:name team)}]] - [:span {:class (stl/css :team-text) :title (:name team)} (:name team)]]) - - [:span {:class (stl/css :switch-icon)} i/arrow-down]] - - (when-not (:is-default team) - [:button - {:class (stl/css :switch-options) - :on-click handle-show-opts-click - :tab-index "0" - :on-key-down handle-show-opts-keydown} - i/actions])] - - ;; Teams Dropdown - [:& dropdown-menu {:show @show-teams-ddwn? - :on-close handle-close-team - :ids ids - :list-class (stl/css :dropdown :teams-dropdown)} - [:& teams-selector-dropdown-items {:ids ids - :team team - :profile profile - :teams teams}]] - - [:& dropdown-menu {:show @show-team-opts-ddwn? - :on-close #(reset! show-team-opts-ddwn? false) - :ids options-ids - :list-class (stl/css :dropdown :options-dropdown)} - [:& team-options-dropdown {:team team - :profile profile}]]] - - ;; Old css - [:div.sidebar-team-switch - [:div.switch-content - [:button.current-team {:tab-index "0" - :on-click (fn [event] - (dom/stop-propagation event) - (reset! show-teams-ddwn? true)) - :on-key-down (fn [event] - (when (or (kbd/space? event) (kbd/enter? event)) - (dom/prevent-default event) - (reset! show-teams-ddwn? true) - (ts/schedule-on-idle - (fn [] - (let [first-element (dom/get-element (first ids))] - (when first-element - (dom/focus! first-element)))))))} - (if (:is-default team) - [:div.team-name - [:span.team-icon i/logo-icon] - [:span.team-text (tr "dashboard.default-team-name")]] - [:div.team-name - [:span.team-icon - [:img {:src (cf/resolve-team-photo-url team) - :alt (:name team)}]] - [:span.team-text {:title (:name team)} (:name team)]]) - - [:span.switch-icon - i/arrow-down]] - - (when-not (:is-default team) - [:button.switch-options {:on-click (fn [event] - (dom/stop-propagation event) - (reset! show-team-opts-ddwn? true)) - :tab-index "0" - :on-key-down (fn [event] - (when (or (kbd/space? event) (kbd/enter? event)) - (dom/prevent-default event) - (reset! show-team-opts-ddwn? true) - (ts/schedule-on-idle - (fn [] - (let [first-element (dom/get-element (first options-ids))] - (when first-element - (dom/focus! first-element)))))))} - i/actions])] - - ;; Teams Dropdown - [:& dropdown-menu {:show @show-teams-ddwn? - :on-close #(reset! show-teams-ddwn? false) - :ids ids - :list-class "dropdown teams-dropdown"} - [:& teams-selector-dropdown-items {:ids ids - :team team - :profile profile - :teams teams}]] - - [:& dropdown-menu {:show @show-team-opts-ddwn? - :on-close #(reset! show-team-opts-ddwn? false) - :ids options-ids - :list-class "dropdown options-dropdown"} - [:& team-options-dropdown {:team team - :profile profile}]]]))) + [:& dropdown-menu {:show @show-team-opts-ddwn? + :on-close #(reset! show-team-opts-ddwn? false) + :ids options-ids + :list-class (stl/css :dropdown :options-dropdown)} + [:& team-options-dropdown {:team team + :profile profile}]]])) (mf/defc sidebar-content [{:keys [projects profile section team project search-term] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - default-project-id + (let [default-project-id (->> (vals projects) (d/seek :is-default) (:id)) @@ -813,115 +649,61 @@ (remove :is-default) (filter :is-pinned))] - (if new-css-system - [:div {:class (stl/css :sidebar-content)} - [:& sidebar-team-switch {:team team :profile profile}] - [:hr] - [:& sidebar-search {:search-term search-term - :team-id (:id team)}] + [:div {:class (stl/css :sidebar-content)} + [:& sidebar-team-switch {:team team :profile profile}] + [:hr] + [:& sidebar-search {:search-term search-term + :team-id (:id team)}] - [:div {:class (stl/css :sidebar-content-section)} - [:ul {:class (stl/css :sidebar-nav :no-overflow)} - [:li - {:class (stl/css :recent-projects) - :class-name (when projects? (stl/css :current))} - [:& link {:action go-projects - :keyboard-action go-projects-with-key} - [:span {:class (stl/css :element-title)} (tr "labels.projects")]]] + [:div {:class (stl/css :sidebar-content-section)} + [:ul {:class (stl/css :sidebar-nav :no-overflow)} + [:li + {:class (stl/css :recent-projects) + :class-name (when projects? (stl/css :current))} + [:& link {:action go-projects + :keyboard-action go-projects-with-key} + [:span {:class (stl/css :element-title)} (tr "labels.projects")]]] - [:li {:class-name (when drafts? (stl/css :current))} - [:& link {:action go-drafts - :keyboard-action go-drafts-with-key} - [:span {:class (stl/css :element-title)} (tr "labels.drafts")]]] + [:li {:class-name (when drafts? (stl/css :current))} + [:& link {:action go-drafts + :keyboard-action go-drafts-with-key} + [:span {:class (stl/css :element-title)} (tr "labels.drafts")]]] - [:li {:class-name (when libs? (stl/css :current))} - [:& link {:action go-libs - :keyboard-action go-libs-with-key} - [:span {:class (stl/css :element-title)} (tr "labels.shared-libraries")]]]]] + [:li {:class-name (when libs? (stl/css :current))} + [:& link {:action go-libs + :keyboard-action go-libs-with-key} + [:span {:class (stl/css :element-title)} (tr "labels.shared-libraries")]]]]] - [:hr] + [:hr] - [:div {:class (stl/css :sidebar-content-section)} - [:ul {:class (stl/css :sidebar-nav :no-overflow)} - [:li {:class-name (when fonts? (stl/css :current))} - [:& link {:action go-fonts - :keyboard-action go-fonts-with-key - :data-test "fonts"} - [:span {:class (stl/css :element-title)} (tr "labels.fonts")]]]]] - - [:hr] - [:div {:class (stl/css :sidebar-content-section) - :data-test "pinned-projects"} - (if (seq pinned-projects) - [:ul {:class (stl/css :sidebar-nav)} - (for [item pinned-projects] - [:& sidebar-project - {:item item - :key (dm/str (:id item)) - :id (:id item) - :team-id (:id team) - :selected? (= (:id item) (:id project))}])] - [:div {:class (stl/css :sidebar-empty-placeholder)} - [:span {:class (stl/css :icon)} i/pin] - [:span {:class (stl/css :text)} (tr "dashboard.no-projects-placeholder")]])]] - - ;; OLD STYLES - [:div.sidebar-content - [:& sidebar-team-switch {:team team :profile profile}] - [:hr] - [:& sidebar-search {:search-term search-term - :team-id (:id team)}] - [:div.sidebar-content-section - [:ul.sidebar-nav.no-overflow - [:li.recent-projects - {:class-name (when projects? "current")} - [:& link {:action go-projects - :keyboard-action go-projects-with-key} - [:span.element-title (tr "labels.projects")]]] - - [:li {:class-name (when drafts? "current")} - [:& link {:action go-drafts - :keyboard-action go-drafts-with-key} - [:span.element-title (tr "labels.drafts")]]] - - - [:li {:class-name (when libs? "current")} - [:& link {:action go-libs - :keyboard-action go-libs-with-key} - [:span.element-title (tr "labels.shared-libraries")]]]]] - - [:hr] - - [:div.sidebar-content-section - [:ul.sidebar-nav.no-overflow - [:li {:class-name (when fonts? "current")} - - [:& link {:action go-fonts - :keyboard-action go-fonts-with-key - :data-test "fonts"} - [:span.element-title (tr "labels.fonts")]]]]] - - [:hr] - [:div.sidebar-content-section {:data-test "pinned-projects"} - (if (seq pinned-projects) - [:ul.sidebar-nav - (for [item pinned-projects] - [:& sidebar-project - {:item item - :key (dm/str (:id item)) - :id (:id item) - :team-id (:id team) - :selected? (= (:id item) (:id project))}])] - [:div.sidebar-empty-placeholder - [:span.icon i/pin] - [:span.text (tr "dashboard.no-projects-placeholder")]])]]))) + [:div {:class (stl/css :sidebar-content-section)} + [:ul {:class (stl/css :sidebar-nav :no-overflow)} + [:li {:class-name (when fonts? (stl/css :current))} + [:& link {:action go-fonts + :keyboard-action go-fonts-with-key + :data-test "fonts"} + [:span {:class (stl/css :element-title)} (tr "labels.fonts")]]]]] + [:hr] + [:div {:class (stl/css :sidebar-content-section) + :data-test "pinned-projects"} + (if (seq pinned-projects) + [:ul {:class (stl/css :sidebar-nav)} + (for [item pinned-projects] + [:& sidebar-project + {:item item + :key (dm/str (:id item)) + :id (:id item) + :team-id (:id team) + :selected? (= (:id item) (:id project))}])] + [:div {:class (stl/css :sidebar-empty-placeholder)} + [:span {:class (stl/css :icon)} i/pin] + [:span {:class (stl/css :text)} (tr "dashboard.no-projects-placeholder")]])]])) (mf/defc profile-section [{:keys [profile team] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - show (mf/use-state false) + (let [show (mf/use-state false) photo (cf/resolve-profile-photo-url profile) on-click @@ -1024,236 +806,110 @@ (fn [event] (when (kbd/enter? event) (on-click (du/logout) event))))] - (if new-css-system - [:* - (when (and team profile) - [:& comments-section - {:profile profile - :team team - :show? show-comments? - :on-show-comments handle-show-comments - :on-hide-comments handle-hide-comments}]) - [:div {:class (stl/css :profile-section)} - [:div {:class (stl/css :profile) - :tab-index "0" - :on-click handle-click - :on-key-down handle-key-down - :data-test "profile-btn"} - [:img {:src photo - :alt (:fullname profile)}] - [:span (:fullname profile)]] + [:* + (when (and team profile) + [:& comments-section + {:profile profile + :team team + :show? show-comments? + :on-show-comments handle-show-comments + :on-hide-comments handle-hide-comments}]) - [:& dropdown-menu {:on-close handle-close :show @show} - [:ul {:class (stl/css :dropdown)} - [:li {:tab-index (if @show "0" "-1") - :on-click (partial on-click :settings-profile) - :on-key-down handle-key-down-profile - :data-test "profile-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.your-account")]] + [:div {:class (stl/css :profile-section)} + [:div {:class (stl/css :profile) + :tab-index "0" + :on-click handle-click + :on-key-down handle-key-down + :data-test "profile-btn"} + [:img {:src photo + :alt (:fullname profile)}] + [:span (:fullname profile)]] + [:& dropdown-menu {:on-close handle-close :show @show} + [:ul {:class (stl/css :dropdown)} + [:li {:tab-index (if @show "0" "-1") + :on-click (partial on-click :settings-profile) + :on-key-down handle-key-down-profile + :data-test "profile-profile-opt"} + [:span {:class (stl/css :text)} (tr "labels.your-account")]] + + [:li {:class (stl/css :separator) + :tab-index (if @show "0" "-1") + :data-url "https://help.penpot.app" + :on-click handle-click-url + :on-key-down handle-keydown-url + :data-test "help-center-profile-opt"} + [:span {:class (stl/css :text)} (tr "labels.help-center")]] + + [:li {:tab-index (if @show "0" "-1") + :data-url "https://community.penpot.app" + :on-click handle-click-url + :on-key-down handle-keydown-url} + [:span {:class (stl/css :text)} (tr "labels.community")]] + + [:li {:tab-index (if @show "0" "-1") + :data-url "https://www.youtube.com/c/Penpot" + :on-click handle-click-url + :on-key-down handle-keydown-url} + [:span {:class (stl/css :text)} (tr "labels.tutorials")]] + + [:li {:tab-index (if @show "0" "-1") + :on-click show-release-notes + :on-key-down handle-show-release-notes} + [:span {:class (stl/css :text)} (tr "labels.release-notes")]] + + [:li {:class (stl/css :separator) + :tab-index (if @show "0" "-1") + :data-url "https://penpot.app/libraries-templates" + :on-click handle-click-url + :on-key-down handle-keydown-url + :data-test "libraries-templates-profile-opt"} + [:span {:class (stl/css :text)} (tr "labels.libraries-and-templates")]] + + [:li {:tab-index (if @show "0" "-1") + :data-url "https://github.com/penpot/penpot" + :on-click handle-click-url + :on-key-down handle-keydown-url} + [:span {:class (stl/css :text)} (tr "labels.github-repo")]] + + [:li {:tab-index (if @show "0" "-1") + :data-url "https://penpot.app/terms" + :on-click handle-click-url + :on-key-down handle-keydown-url} + [:span {:class (stl/css :text)} (tr "auth.terms-of-service")]] + + (when (contains? cf/flags :user-feedback) [:li {:class (stl/css :separator) :tab-index (if @show "0" "-1") - :data-url "https://help.penpot.app" - :on-click handle-click-url - :on-key-down handle-keydown-url - :data-test "help-center-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.help-center")]] + :on-click handle-feedback-click + :on-key-down handle-feedback-keydown + :data-test "feedback-profile-opt"} + [:span {:class (stl/css :text)} (tr "labels.give-feedback")]]) - [:li {:tab-index (if @show "0" "-1") - :data-url "https://community.penpot.app" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "labels.community")]] + [:li {:class (stl/css :separator) + :tab-index (if @show "0" "-1") + :on-click handle-logout-click + :on-key-down handle-logout-keydown + :data-test "logout-profile-opt"} + [:span {:class (stl/css :icon)} i/exit] + [:span {:class (stl/css :text)} (tr "labels.logout")]]]] - [:li {:tab-index (if @show "0" "-1") - :data-url "https://www.youtube.com/c/Penpot" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "labels.tutorials")]] - - [:li {:tab-index (if @show "0" "-1") - :on-click show-release-notes - :on-key-down handle-show-release-notes} - [:span {:class (stl/css :text)} (tr "labels.release-notes")]] - - [:li {:class (stl/css :separator) - :tab-index (if @show "0" "-1") - :data-url "https://penpot.app/libraries-templates" - :on-click handle-click-url - :on-key-down handle-keydown-url - :data-test "libraries-templates-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.libraries-and-templates")]] - - [:li {:tab-index (if @show "0" "-1") - :data-url "https://github.com/penpot/penpot" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "labels.github-repo")]] - - [:li {:tab-index (if @show "0" "-1") - :data-url "https://penpot.app/terms" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "auth.terms-of-service")]] - - (when (contains? cf/flags :user-feedback) - [:li {:class (stl/css :separator) - :tab-index (if @show "0" "-1") - :on-click handle-feedback-click - :on-key-down handle-feedback-keydown - :data-test "feedback-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.give-feedback")]]) - - [:li {:class (stl/css :separator) - :tab-index (if @show "0" "-1") - :on-click handle-logout-click - :on-key-down handle-logout-keydown - :data-test "logout-profile-opt"} - [:span {:class (stl/css :icon)} i/exit] - [:span {:class (stl/css :text)} (tr "labels.logout")]]]] - - (when (and team profile) - [:& comments-icon - {:profile profile - :show? show-comments? - :on-show-comments handle-show-comments}])]] - - ;; OLD - [:div.profile-section - [:div.profile {:tab-index "0" - :on-click (fn [event] - (dom/stop-propagation event) - (reset! show true)) - :on-key-down (fn [event] - (when (kbd/enter? event) - (reset! show true))) - :data-test "profile-btn"} - [:img {:src photo - :alt (:fullname profile)}] - [:span (:fullname profile)]] - - [:& dropdown-menu {:on-close (fn [event] - (dom/stop-propagation event) - (reset! show false)) - :show @show} - [:ul.dropdown - [:li {:tab-index (if show - "0" - "-1") - :on-click (partial on-click :settings-profile) - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-click :settings-profile event))) - :data-test "profile-profile-opt"} - [:span.text (tr "labels.your-account")]] - [:li.separator {:tab-index (if show - "0" - "-1") - :on-click #(dom/open-new-window "https://help.penpot.app") - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/open-new-window "https://help.penpot.app"))) - :data-test "help-center-profile-opt"} - [:span.text (tr "labels.help-center")]] - [:li {:tab-index (if show - "0" - "-1") - :on-click #(dom/open-new-window "https://community.penpot.app") - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/open-new-window "https://community.penpot.app")))} - [:span.text (tr "labels.community")]] - [:li {:tab-index (if show - "0" - "-1") - :on-click #(dom/open-new-window "https://www.youtube.com/c/Penpot") - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/open-new-window "https://www.youtube.com/c/Penpot")))} - [:span.text (tr "labels.tutorials")]] - [:li {:tab-index (if show - "0" - "-1") - :on-click show-release-notes - :on-key-down (fn [event] - (when (kbd/enter? event) - (show-release-notes)))} - [:span (tr "labels.release-notes")]] - - [:li.separator {:tab-index (if show - "0" - "-1") - :on-click #(dom/open-new-window "https://penpot.app/libraries-templates") - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/open-new-window "https://penpot.app/libraries-templates"))) - :data-test "libraries-templates-profile-opt"} - [:span.text (tr "labels.libraries-and-templates")]] - [:li {:tab-index (if show - "0" - "-1") - :on-click #(dom/open-new-window "https://github.com/penpot/penpot") - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/open-new-window "https://github.com/penpot/penpot")))} - [:span (tr "labels.github-repo")]] - [:li {:tab-index (if show - "0" - "-1") - :on-click #(dom/open-new-window "https://penpot.app/terms") - :on-key-down (fn [event] - (when (kbd/enter? event) - (dom/open-new-window "https://penpot.app/terms")))} - [:span (tr "auth.terms-of-service")]] - - (when (contains? cf/flags :user-feedback) - [:li.separator {:tab-index (if show - "0" - "-1") - :on-click (partial on-click :settings-feedback) - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-click :settings-feedback event))) - :data-test "feedback-profile-opt"} - [:span.text (tr "labels.give-feedback")]]) - - [:li.separator {:tab-index (if show - "0" - "-1") - :on-click #(on-click (du/logout) %) - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-click (du/logout) event))) - :data-test "logout-profile-opt"} - [:span.icon i/exit] - [:span.text (tr "labels.logout")]]]] - - (when (and team profile) - [:& comments-section - {:profile profile - :team team - :show? show-comments? - :on-show-comments handle-show-comments - :on-hide-comments handle-hide-comments}])]))) + (when (and team profile) + [:& comments-icon + {:profile profile + :show? show-comments? + :on-show-comments handle-show-comments}])]])) (mf/defc sidebar {::mf/wrap-props false ::mf/wrap [mf/memo]} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - team (obj/get props "team") + (let [team (obj/get props "team") profile (obj/get props "profile")] - (if new-css-system - [:nav {:class (stl/css :dashboard-sidebar)} - [:> sidebar-content props] - [:& profile-section - {:profile profile - :team team}]] - - [:nav.dashboard-sidebar - [:> sidebar-content props] - [:& profile-section - {:profile profile - :team team}]]))) + [:nav {:class (stl/css :dashboard-sidebar)} + [:> sidebar-content props] + [:& profile-section + {:profile profile + :team team}]])) diff --git a/frontend/src/app/main/ui/dashboard/team.scss b/frontend/src/app/main/ui/dashboard/team.scss index 83c5eff7ca..d593616b2d 100644 --- a/frontend/src/app/main/ui/dashboard/team.scss +++ b/frontend/src/app/main/ui/dashboard/team.scss @@ -102,7 +102,7 @@ } } .btn-primary { - @extends .button-primary; + @extend .button-primary; height: $s-32; } } @@ -650,6 +650,7 @@ color: var(--modal-title-foreground-color); } } + .invitation-row { margin-top: $s-8; margin-bottom: $s-24; @@ -671,48 +672,56 @@ .modal-overlay { @extend .modal-overlay-base; - .modal-container { - @extend .modal-container-base; - border: $s-1 solid var(--modal-border-color); - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } +} - .modal-content { - @include flexColumn; - gap: $s-24; - @include titleTipography; - margin-bottom: $s-24; +.modal-container { + @extend .modal-container-base; + border: $s-1 solid var(--modal-border-color); +} - .fields-row { - @include flexColumn; - .select-title { - @include titleTipography; - color: var(--modal-title-foreground-color); - } - .custom-input-checkbox { - align-items: flex-start; - } - } - } +.modal-header { + margin-bottom: $s-24; +} - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - button { - @extend .modal-accept-btn; - } - .cancel-button { - @extend .modal-cancel-btn; - } - } - } +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include flexColumn; + gap: $s-24; + @include titleTipography; + margin-bottom: $s-24; +} + +.fields-row { + @include flexColumn; +} + +.select-title { + @include titleTipography; + color: var(--modal-title-foreground-color); +} + +.custom-input-checkbox { + align-items: flex-start; +} + +.hint { + color: var(--modal-text-foreground-color); +} + +.action-buttons { + @extend .modal-action-btns; + button { + @extend .modal-accept-btn; + } + .cancel-button { + @extend .modal-cancel-btn; } } diff --git a/frontend/src/app/main/ui/dashboard/templates.cljs b/frontend/src/app/main/ui/dashboard/templates.cljs index c733d4f3e5..8b61fc95b8 100644 --- a/frontend/src/app/main/ui/dashboard/templates.cljs +++ b/frontend/src/app/main/ui/dashboard/templates.cljs @@ -16,7 +16,6 @@ [app.main.data.users :as du] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :refer [tr]] @@ -59,8 +58,7 @@ (mf/defc title {::mf/wrap-props false} [{:keys [collapsed]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - on-click + (let [on-click (mf/use-fn (mf/deps collapsed) (fn [_event] @@ -76,27 +74,17 @@ (dom/prevent-default event) (on-click event))))] - (if new-css-system - [:div {:class (stl/css :title)} - [:button {:tab-index "0" - :on-click on-click - :on-key-down on-key-down} - [:span (tr "dashboard.libraries-and-templates")] - [:span {:class (stl/css :icon)} (if ^boolean collapsed i/arrow-up i/arrow-down)]]] - - ;; OLD - [:div.title - [:button {:tab-index "0" - :on-click on-click - :on-key-down on-key-down} - [:span (tr "dashboard.libraries-and-templates")] - [:span.icon (if ^boolean collapsed i/arrow-up i/arrow-down)]]]))) + [:div {:class (stl/css :title)} + [:button {:tab-index "0" + :on-click on-click + :on-key-down on-key-down} + [:span (tr "dashboard.libraries-and-templates")] + [:span {:class (stl/css :icon)} (if ^boolean collapsed i/arrow-up i/arrow-down)]]])) (mf/defc card-item {::mf/wrap-props false} [{:keys [item index is-visible collapsed on-import]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - id (dm/str "card-container-" index) + (let [id (dm/str "card-container-" index) thb (assoc cf/public-uri :path (dm/str "/images/thumbnails/template-" (:id item) ".jpg")) on-click @@ -113,41 +101,24 @@ (dom/stop-propagation event) (on-import item event))))] - (if new-css-system - [:a - {:class (stl/css :card-container) - :tab-index (if (or (not is-visible) collapsed) "-1" "0") - :id id - :data-index index - :on-click on-click - :on-key-down on-key-down} - [:div {:class (stl/css :template-card)} - [:div {:class (stl/css :img-container)} - [:img {:src (dm/str thb) - :alt (:name item)}]] - [:div {:class (stl/css :card-name)} - [:span (:name item)] - [:span {:class (stl/css :icon)} i/download]]]] - - ;; OLD - [:a.card-container - {:tab-index (if (or (not is-visible) collapsed) "-1" "0") - :id id - :data-index index - :on-click on-click - :on-key-down on-key-down} - [:div.template-card - [:div.img-container - [:img {:src (dm/str thb) - :alt (:name item)}]] - [:div.card-name [:span (:name item)] - [:span.icon i/download]]]]))) + [:a {:class (stl/css :card-container) + :tab-index (if (or (not is-visible) collapsed) "-1" "0") + :id id + :data-index index + :on-click on-click + :on-key-down on-key-down} + [:div {:class (stl/css :template-card)} + [:div {:class (stl/css :img-container)} + [:img {:src (dm/str thb) + :alt (:name item)}]] + [:div {:class (stl/css :card-name)} + [:span (:name item)] + [:span {:class (stl/css :icon)} i/download]]]])) (mf/defc card-item-link {::mf/wrap-props false} [{:keys [total is-visible collapsed section]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - id (dm/str "card-container-" total) + (let [id (dm/str "card-container-" total) on-click (mf/use-fn @@ -165,39 +136,23 @@ (dom/stop-propagation event) (on-click event))))] - (if new-css-system - [:div {:class (stl/css :card-container)} - [:div {:class (stl/css :template-card)} - [:div {:class (stl/css :img-container)} - [:a {:id id - :tab-index (if (or (not is-visible) collapsed) "-1" "0") - :href "https://penpot.app/libraries-templates.html" - :target "_blank" - :on-click on-click - :on-key-down on-key-down} - [:div {:class (stl/css :template-link)} - [:div {:class (stl/css :template-link-title)} (tr "dashboard.libraries-and-templates")] - [:div {:class (stl/css :template-link-text)} (tr "dashboard.libraries-and-templates.explore")]]]]]] - - ;; OLD - [:div.card-container - [:div.template-card - [:div.img-container - [:a {:id id - :tab-index (if (or (not is-visible) collapsed) "-1" "0") - :href "https://penpot.app/libraries-templates.html" - :target "_blank" - :on-click on-click - :on-key-down on-key-down} - [:div.template-link - [:div.template-link-title (tr "dashboard.libraries-and-templates")] - [:div.template-link-text (tr "dashboard.libraries-and-templates.explore")]]]]]]))) + [:div {:class (stl/css :card-container)} + [:div {:class (stl/css :template-card)} + [:div {:class (stl/css :img-container)} + [:a {:id id + :tab-index (if (or (not is-visible) collapsed) "-1" "0") + :href "https://penpot.app/libraries-templates.html" + :target "_blank" + :on-click on-click + :on-key-down on-key-down} + [:div {:class (stl/css :template-link)} + [:div {:class (stl/css :template-link-title)} (tr "dashboard.libraries-and-templates")] + [:div {:class (stl/css :template-link-text)} (tr "dashboard.libraries-and-templates.explore")]]]]]])) (mf/defc templates-section {::mf/wrap-props false} [{:keys [default-project-id profile project-id team-id content-width]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - templates (mf/deref builtin-templates) + (let [templates (mf/deref builtin-templates) templates (mf/with-memo [templates] (filterv #(not= (:id %) "tutorial-for-beginners") templates)) @@ -273,94 +228,50 @@ (mf/use-fn (mf/deps default-project-id project-id section templates team-id) (fn [template _event] - (import-template! template team-id project-id default-project-id section))) - - ] + (import-template! template team-id project-id default-project-id section)))] (mf/with-effect [profile collapsed] (when (and profile (not collapsed)) (st/emit! (dd/fetch-builtin-templates)))) - (if new-css-system - [:div - {:class (stl/css-case :dashboard-templates-section true - :collapsed collapsed)} - [:& title {:collapsed collapsed}] + [:div {:class (stl/css-case :dashboard-templates-section true + :collapsed collapsed)} + [:& title {:collapsed collapsed}] - [:div {:class (stl/css :content) - :ref content-ref - :style {:left card-offset - :width (dm/str container-size "px")}} + [:div {:class (stl/css :content) + :ref content-ref + :style {:left card-offset + :width (dm/str container-size "px")}} - (for [index (range (count templates))] - [:& card-item - {:on-import on-import-template - :item (nth templates index) - :index index - :key index - :is-visible (and (>= index first-card) - (<= index last-card)) - :collapsed collapsed}]) + (for [index (range (count templates))] + [:& card-item + {:on-import on-import-template + :item (nth templates index) + :index index + :key index + :is-visible (and (>= index first-card) + (<= index last-card)) + :collapsed collapsed}]) - [:& card-item-link - {:is-visible (and (>= total first-card) (<= total last-card)) - :collapsed collapsed - :section section - :total total}]] + [:& card-item-link + {:is-visible (and (>= total first-card) (<= total last-card)) + :collapsed collapsed + :section section + :total total}]] - (when (< card-offset 0) - [:button - {:class (stl/css :button :left) - :tab-index (if ^boolean collapsed "-1" "0") - :on-click on-move-left - :on-key-down on-move-left-key-down} - i/go-prev]) + (when (< card-offset 0) + [:button + {:class (stl/css :button :left) + :tab-index (if ^boolean collapsed "-1" "0") + :on-click on-move-left + :on-key-down on-move-left-key-down} + i/go-prev]) - (when more-cards - [:button - {:class (stl/css :button :right) - :tab-index (if collapsed "-1" "0") - :on-click on-move-right - :aria-label (tr "labels.next") - :on-key-down on-move-right-key-down} - i/go-next])] - - ;; OLD - [:div.dashboard-templates-section - {:class (when ^boolean collapsed "collapsed")} - [:& title {:collapsed collapsed}] - - [:div.content {:ref content-ref - :style {:left card-offset - :width (dm/str container-size "px")}} - - (for [index (range (count templates))] - [:& card-item - {:on-import on-import-template - :item (nth templates index) - :index index - :key index - :is-visible (and (>= index first-card) - (<= index last-card)) - :collapsed collapsed}]) - - [:& card-item-link - {:is-visible (and (>= total first-card) (<= total last-card)) - :collapsed collapsed - :section section - :total total}]] - - (when (< card-offset 0) - [:button.button.left - {:tab-index (if ^boolean collapsed "-1" "0") - :on-click on-move-left - :on-key-down on-move-left-key-down} - i/go-prev]) - - (when more-cards - [:button.button.right - {:tab-index (if collapsed "-1" "0") - :on-click on-move-right - :aria-label (tr "labels.next") - :on-key-down on-move-right-key-down} - i/go-next])]))) + (when more-cards + [:button + {:class (stl/css :button :right) + :tab-index (if collapsed "-1" "0") + :on-click on-move-right + :aria-label (tr "labels.next") + :on-key-down on-move-right-key-down} + i/go-next])])) diff --git a/frontend/src/app/main/ui/onboarding/questions.cljs b/frontend/src/app/main/ui/onboarding/questions.cljs index 1f5d4b9f46..4f9a612158 100644 --- a/frontend/src/app/main/ui/onboarding/questions.cljs +++ b/frontend/src/app/main/ui/onboarding/questions.cljs @@ -13,7 +13,6 @@ [app.main.data.users :as du] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.util.i18n :as i18n :refer [tr]] [cljs.spec.alpha :as s] [cuerdas.core :as str] @@ -22,139 +21,75 @@ (mf/defc step-container [{:keys [form step on-next on-prev children] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] + [:& fm/form {:form form :on-submit on-next} + [:div {:class (stl/css :paginator)} (str/ffmt "%/4" step)] - (if new-css-system - [:& fm/form {:form form :on-submit on-next} - [:div {:class (stl/css :paginator)} (str/ffmt "%/4" step)] + children - children + [:div {:class (stl/css :action-buttons)} - [:div {:class (stl/css :action-buttons)} + (when on-prev + [:button {:class (stl/css :prev-button) + :on-click on-prev} (tr "questions.previous")]) - (when on-prev - [:button {:class (stl/css :prev-button) - :on-click on-prev} (tr "questions.previous")]) - - [:> fm/submit-button* - {:label (if (< step 4) (tr "questions.next") (tr "questions.start")) - :class (stl/css :next-button)}]]] - - - - [:& fm/form {:form form :on-submit on-next} - [:div.step-header - [:div.step-number (str/ffmt "%/4" step)]] - - children - - [:div.buttons - [:div.step-next - [:> fm/submit-button* - {:label (if (< step 4) (tr "questions.next") (tr "questions.start")) - :class "step-next"}]] - - (when on-prev - [:div.step-prev - [:button {:on-click on-prev} (tr "questions.previous")]])]]))) + [:> fm/submit-button* + {:label (if (< step 4) (tr "questions.next") (tr "questions.start")) + :class (stl/css :next-button)}]]]) (s/def ::questions-form-step-1 (s/keys :req-un [::planning])) (mf/defc step-1 [{:keys [on-next form] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& step-container {:form form :step 1 :on-next on-next} - [:img {:class (stl/css :header-image) - :src "images/form/use-for-1.png" :alt (tr "questions.lets-get-started")}] - [:h1 {:class (stl/css :modal-title)} (tr "questions.lets-get-started")] - [:p {:class (stl/css :modal-text)} (tr "questions.your-feedback-will-help-us")] - [:h3 {:class (stl/css :modal-subtitle)} (tr "questions.questions-how-are-you-planning-to-use-penpot")] - [:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "questions-how-are-you-planning-to-use-penpot" :disabled true} - {:label (tr "questions.discover-more-about-penpot") :value "discover-more-about-penpot" :key "discover-more-about-penpot"} - {:label (tr "questions.test-penpot-to-see-if-its-a-fit-for-team") :value "test-penpot-to-see-if-its-a-fit-for-team" :key "test-penpot-to-see-if-its-a-fit-for-team"} - {:label (tr "questions.start-to-work-on-my-project") :value "start-to-work-on-my-project" :key "start-to-work-on-my-project"} - {:label (tr "questions.get-the-code-from-my-team-project") :value "get-the-code-from-my-team-project" :key "get-the-code-from-my-team-project"} - {:label (tr "questions.leave-feedback-for-my-team-project") :value "leave-feedback-for-my-team-project" :key "leave-feedback-for-my-team-project"} - {:label (tr "questions.work-in-concept-ideas") :value "work-in-concept-ideas" :key "work-in-concept-ideas"} - {:label (tr "questions.try-out-before-using-penpot-on-premise") :value "try-out-before-using-penpot-on-premise" :key "try-out-before-using-penpot-on-premise"}] - :default "" - :name :planning}]] - - - [:& step-container {:form form :step 1 :on-next on-next} - [:img.header-image {:src "images/form/use-for-1.png" :alt (tr "questions.lets-get-started")}] - [:h1 (tr "questions.lets-get-started")] - [:p.intro (tr "questions.your-feedback-will-help-us")] - [:h3 (tr "questions.questions-how-are-you-planning-to-use-penpot")] - [:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "questions-how-are-you-planning-to-use-penpot" :disabled true} - {:label (tr "questions.discover-more-about-penpot") :value "discover-more-about-penpot" :key "discover-more-about-penpot"} - {:label (tr "questions.test-penpot-to-see-if-its-a-fit-for-team") :value "test-penpot-to-see-if-its-a-fit-for-team" :key "test-penpot-to-see-if-its-a-fit-for-team"} - {:label (tr "questions.start-to-work-on-my-project") :value "start-to-work-on-my-project" :key "start-to-work-on-my-project"} - {:label (tr "questions.get-the-code-from-my-team-project") :value "get-the-code-from-my-team-project" :key "get-the-code-from-my-team-project"} - {:label (tr "questions.leave-feedback-for-my-team-project") :value "leave-feedback-for-my-team-project" :key "leave-feedback-for-my-team-project"} - {:label (tr "questions.work-in-concept-ideas") :value "work-in-concept-ideas" :key "work-in-concept-ideas"} - {:label (tr "questions.try-out-before-using-penpot-on-premise") :value "try-out-before-using-penpot-on-premise" :key "try-out-before-using-penpot-on-premise"}] - :default "" - :name :planning}]]))) + [:& step-container {:form form :step 1 :on-next on-next} + [:img {:class (stl/css :header-image) + :src "images/form/use-for-1.png" :alt (tr "questions.lets-get-started")}] + [:h1 {:class (stl/css :modal-title)} (tr "questions.lets-get-started")] + [:p {:class (stl/css :modal-text)} (tr "questions.your-feedback-will-help-us")] + [:h3 {:class (stl/css :modal-subtitle)} (tr "questions.questions-how-are-you-planning-to-use-penpot")] + [:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "questions-how-are-you-planning-to-use-penpot" :disabled true} + {:label (tr "questions.discover-more-about-penpot") :value "discover-more-about-penpot" :key "discover-more-about-penpot"} + {:label (tr "questions.test-penpot-to-see-if-its-a-fit-for-team") :value "test-penpot-to-see-if-its-a-fit-for-team" :key "test-penpot-to-see-if-its-a-fit-for-team"} + {:label (tr "questions.start-to-work-on-my-project") :value "start-to-work-on-my-project" :key "start-to-work-on-my-project"} + {:label (tr "questions.get-the-code-from-my-team-project") :value "get-the-code-from-my-team-project" :key "get-the-code-from-my-team-project"} + {:label (tr "questions.leave-feedback-for-my-team-project") :value "leave-feedback-for-my-team-project" :key "leave-feedback-for-my-team-project"} + {:label (tr "questions.work-in-concept-ideas") :value "work-in-concept-ideas" :key "work-in-concept-ideas"} + {:label (tr "questions.try-out-before-using-penpot-on-premise") :value "try-out-before-using-penpot-on-premise" :key "try-out-before-using-penpot-on-premise"}] + :default "" + :name :planning}]]) (s/def ::questions-form-step-2 (s/keys :req-un [::experience-branding-illustrations-marketing-pieces ::experience-interface-design-visual-assets-design-systems ::experience-interface-wireframes-user-journeys-flows-navigation-trees])) (mf/defc step-2 [{:keys [on-next on-prev form] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:& step-container {:form form :step 2 :on-next on-next :on-prev on-prev} - [:h3 {:class (stl/css :modal-subtitle)} - (tr "questions.describe-your-experience-working-on")] + [:& step-container {:form form :step 2 :on-next on-next :on-prev on-prev} + [:h3 {:class (stl/css :modal-subtitle)} + (tr "questions.describe-your-experience-working-on")] - [:div {:class (stl/css :modal-question)} - [:div {:class (stl/css :modal-text)} - (tr "branding-illustrations-marketing-pieces")] - [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} - {:label (tr "questions.some") :value "some"} - {:label (tr "questions.a-lot") :value "a-lot"}] - :name :experience-branding-illustrations-marketing-pieces}]] + [:div {:class (stl/css :modal-question)} + [:div {:class (stl/css :modal-text)} + (tr "branding-illustrations-marketing-pieces")] + [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} + {:label (tr "questions.some") :value "some"} + {:label (tr "questions.a-lot") :value "a-lot"}] + :name :experience-branding-illustrations-marketing-pieces}]] - [:div {:class (stl/css :modal-question)} - [:div {:class (stl/css :modal-text)} - (tr "questions.interface-design-visual-assets-design-systems")] - [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} - {:label (tr "questions.some") :value "some"} - {:label (tr "questions.a-lot") :value "a-lot"}] - :name :experience-interface-design-visual-assets-design-systems}]] + [:div {:class (stl/css :modal-question)} + [:div {:class (stl/css :modal-text)} + (tr "questions.interface-design-visual-assets-design-systems")] + [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} + {:label (tr "questions.some") :value "some"} + {:label (tr "questions.a-lot") :value "a-lot"}] + :name :experience-interface-design-visual-assets-design-systems}]] - [:div {:class (stl/css :modal-question)} - [:div {:class (stl/css :modal-text)} - (tr "questions.wireframes-user-journeys-flows-navigation-trees")] - [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} - {:label (tr "questions.some") :value "some"} - {:label (tr "questions.a-lot") :value "a-lot"}] - :name :experience-interface-wireframes-user-journeys-flows-navigation-trees}]]] - - - [:& step-container {:form form :step 2 :on-next on-next :on-prev on-prev} - [:h3 (tr "questions.describe-your-experience-working-on")] - - [:div.section (tr "branding-illustrations-marketing-pieces")] - [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} - {:label (tr "questions.some") :value "some"} - {:label (tr "questions.a-lot") :value "a-lot"}] - :name :experience-branding-illustrations-marketing-pieces}] - - [:div.section (tr "questions.interface-design-visual-assets-design-systems")] - [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} - {:label (tr "questions.some") :value "some"} - {:label (tr "questions.a-lot") :value "a-lot"}] - :name :experience-interface-design-visual-assets-design-systems}] - - [:div.section (tr "questions.wireframes-user-journeys-flows-navigation-trees")] - [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} - {:label (tr "questions.some") :value "some"} - {:label (tr "questions.a-lot") :value "a-lot"}] - :name :experience-interface-wireframes-user-journeys-flows-navigation-trees}]]))) + [:div {:class (stl/css :modal-question)} + [:div {:class (stl/css :modal-text)} + (tr "questions.wireframes-user-journeys-flows-navigation-trees")] + [:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"} + {:label (tr "questions.some") :value "some"} + {:label (tr "questions.a-lot") :value "a-lot"}] + :name :experience-interface-wireframes-user-journeys-flows-navigation-trees}]]]) (s/def ::questions-form-step-3 (s/keys :req-un [::experience-design-tool] @@ -170,8 +105,7 @@ (mf/defc step-3 [{:keys [on-next on-prev form] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool]) + (let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool]) on-design-tool-change (fn [_ _] (let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])] @@ -180,40 +114,23 @@ (swap! form d/dissoc-in [:data :experience-design-tool-other]) (swap! form d/dissoc-in [:errors :experience-design-tool-other])))))] - (if new-css-system - [:& step-container {:form form :step 3 :on-next on-next :on-prev on-prev} - [:h3 {:class (stl/css :modal-subtitle)} - (tr "question.design-tool-more-experienced-with")] - [:& fm/radio-buttons {:options [{:label (tr "questions.figma") :value "figma" :image "images/form/figma.png"} - {:label (tr "questions.sketch") :value "sketch" :image "images/form/sketch.png"} - {:label (tr "questions.adobe-xd") :value "adobe-xd" :image "images/form/adobe-xd.png"} - {:label (tr "questions.canva") :value "canva" :image "images/form/canva.png"} - {:label (tr "questions.invision") :value "invision" :image "images/form/invision.png"} - {:label (tr "questions.never-used-a-tool") :value "never-used-a-tool" :image "images/form/never-used.png"} - {:label (tr "questions.other") :value "other"}] - :name :experience-design-tool - :on-change on-design-tool-change}] + [:& step-container {:form form :step 3 :on-next on-next :on-prev on-prev} + [:h3 {:class (stl/css :modal-subtitle)} + (tr "question.design-tool-more-experienced-with")] + [:& fm/radio-buttons {:options [{:label (tr "questions.figma") :value "figma" :image "images/form/figma.png"} + {:label (tr "questions.sketch") :value "sketch" :image "images/form/sketch.png"} + {:label (tr "questions.adobe-xd") :value "adobe-xd" :image "images/form/adobe-xd.png"} + {:label (tr "questions.canva") :value "canva" :image "images/form/canva.png"} + {:label (tr "questions.invision") :value "invision" :image "images/form/invision.png"} + {:label (tr "questions.never-used-a-tool") :value "never-used-a-tool" :image "images/form/never-used.png"} + {:label (tr "questions.other") :value "other"}] + :name :experience-design-tool + :on-change on-design-tool-change}] - [:& fm/input {:name :experience-design-tool-other - :placeholder (tr "questions.other") - :label "" - :disabled (not= experience-design-tool "other")}]] - - - [:& step-container {:form form :step 3 :on-next on-next :on-prev on-prev} - [:h3 (tr "question.design-tool-more-experienced-with")] - [:& fm/radio-buttons {:options [{:label (tr "questions.figma") :value "figma" :image "images/form/figma.png"} - {:label (tr "questions.sketch") :value "sketch" :image "images/form/sketch.png"} - {:label (tr "questions.adobe-xd") :value "adobe-xd" :image "images/form/adobe-xd.png"} - {:label (tr "questions.canva") :value "canva" :image "images/form/canva.png"} - {:label (tr "questions.invision") :value "invision" :image "images/form/invision.png"} - {:label (tr "questions.never-used-a-tool") :value "never-used-a-tool" :image "images/form/never-used.png"} - {:label (tr "questions.other") :value "other"}] - :name :experience-design-tool - :on-change on-design-tool-change}] - [:div.other - [:label (tr "questions.other")] - [:& fm/input {:name :experience-design-tool-other :label (tr "questions.other") :disabled (not= experience-design-tool "other")}]]]))) + [:& fm/input {:name :experience-design-tool-other + :placeholder (tr "questions.other") + :label "" + :disabled (not= experience-design-tool "other")}]])) (s/def ::questions-form-step-4 (s/keys :req-un [::team-size ::role] @@ -229,8 +146,7 @@ (mf/defc step-4 [{:keys [on-next on-prev form] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - role (dm/get-in @form [:data :role]) + (let [role (dm/get-in @form [:data :role]) on-role-change (fn [_ _] (let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])] @@ -239,63 +155,34 @@ (swap! form d/dissoc-in [:data :role-other]) (swap! form d/dissoc-in [:errors :role-other])))))] - (if new-css-system - [:& step-container {:form form :step 4 :on-next on-next :on-prev on-prev} - [:h3 {:class (stl/css :modal-subtitle)} (tr "questions.role")] - [:& fm/radio-buttons {:options [{:label (tr "questions.designer") :value "designer"} - {:label (tr "questions.developer") :value "developer"} - {:label (tr "questions.manager") :value "manager"} - {:label (tr "questions.founder") :value "founder"} - {:label (tr "questions.marketing") :value "marketing"} - {:label (tr "questions.student-teacher") :value "student-teacher"} - {:label (tr "questions.other") :value "other"}] - :name :role - :on-change on-role-change}] - [:& fm/input {:name :role-other :label "" :placeholder (tr "questions.other") :disabled (not= role "other")}] + [:& step-container {:form form :step 4 :on-next on-next :on-prev on-prev} + [:h3 {:class (stl/css :modal-subtitle)} (tr "questions.role")] + [:& fm/radio-buttons {:options [{:label (tr "questions.designer") :value "designer"} + {:label (tr "questions.developer") :value "developer"} + {:label (tr "questions.manager") :value "manager"} + {:label (tr "questions.founder") :value "founder"} + {:label (tr "questions.marketing") :value "marketing"} + {:label (tr "questions.student-teacher") :value "student-teacher"} + {:label (tr "questions.other") :value "other"}] + :name :role + :on-change on-role-change}] + [:& fm/input {:name :role-other :label "" :placeholder (tr "questions.other") :disabled (not= role "other")}] - [:div {:class (stl/css :modal-question)} - [:h3 {:class (stl/css :modal-subtitle)} (tr "questions.team-size")] - [:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "team-size" :disabled true} - {:label (tr "questions.more-than-50") :value "more-than-50" :key "more-than-50"} - {:label (tr "questions.31-50") :value "31-50" :key "31-50"} - {:label (tr "questions.11-30") :value "11-30" :key "11-30"} - {:label (tr "questions.2-10") :value "2-10" :key "2-10"} - {:label (tr "questions.freelancer") :value "freelancer" :key "freelancer"} - {:label (tr "questions.personal-project") :value "personal-project" :key "personal-project"}] - :default "" - :name :team-size}]]] - - - [:& step-container {:form form :step 4 :on-next on-next :on-prev on-prev} - [:h3 (tr "questions.role")] - [:& fm/radio-buttons {:options [{:label (tr "questions.designer") :value "designer"} - {:label (tr "questions.developer") :value "developer"} - {:label (tr "questions.manager") :value "manager"} - {:label (tr "questions.founder") :value "founder"} - {:label (tr "questions.marketing") :value "marketing"} - {:label (tr "questions.student-teacher") :value "student-teacher"} - {:label (tr "questions.other") :value "other"}] - :name :role - :on-change on-role-change}] - [:div.other - [:label (tr "questions.other")] - [:& fm/input {:name :role-other :label (tr "questions.other") :disabled (not= role "other")}]] - - [:h3 (tr "questions.team-size")] - [:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "team-size" :disabled true} - {:label (tr "questions.more-than-50") :value "more-than-50" :key "more-than-50"} - {:label (tr "questions.31-50") :value "31-50" :key "31-50"} - {:label (tr "questions.11-30") :value "11-30" :key "11-30"} - {:label (tr "questions.2-10") :value "2-10" :key "2-10"} - {:label (tr "questions.freelancer") :value "freelancer" :key "freelancer"} - {:label (tr "questions.personal-project") :value "personal-project" :key "personal-project"}] - :default "" - :name :team-size}]]))) + [:div {:class (stl/css :modal-question)} + [:h3 {:class (stl/css :modal-subtitle)} (tr "questions.team-size")] + [:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "team-size" :disabled true} + {:label (tr "questions.more-than-50") :value "more-than-50" :key "more-than-50"} + {:label (tr "questions.31-50") :value "31-50" :key "31-50"} + {:label (tr "questions.11-30") :value "11-30" :key "11-30"} + {:label (tr "questions.2-10") :value "2-10" :key "2-10"} + {:label (tr "questions.freelancer") :value "freelancer" :key "freelancer"} + {:label (tr "questions.personal-project") :value "personal-project" :key "personal-project"}] + :default "" + :name :team-size}]]])) (mf/defc questions [{:keys []}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - container (mf/use-ref) + (let [container (mf/use-ref) step (mf/use-state 1) clean-data (mf/use-state {}) @@ -336,25 +223,11 @@ (reset! clean-data questionnaire) (st/emit! (du/mark-questions-as-answered questionnaire)))))] - (if new-css-system - [:div {:class (stl/css :modal-overlay)} - [:div {:class (stl/css :modal-container) - :ref container} - (case @step - 1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form}] - 2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form}] - 3 [:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form}] - 4 [:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form}])]] - - - [:div.modal-wrapper.questions-form - [:div.modal-overlay - [:div.modal-container.onboarding.onboarding-v2 {:ref container} - [:img.deco.left {:src "images/deco-left.png" :border 0}] - [:img.deco.right {:src "images/deco-right.png" :border 0}] - [:div.signup-questions - (case @step - 1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form}] - 2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form}] - 3 [:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form}] - 4 [:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form}])]]]]))) + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container) + :ref container} + (case @step + 1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form}] + 2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form}] + 3 [:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form}] + 4 [:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form}])]])) diff --git a/frontend/src/app/main/ui/settings.cljs b/frontend/src/app/main/ui/settings.cljs index 946f6f1c6c..8b024332d5 100644 --- a/frontend/src/app/main/ui/settings.cljs +++ b/frontend/src/app/main/ui/settings.cljs @@ -10,7 +10,6 @@ [app.main.data.dashboard.shortcuts :as sc] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.settings.access-tokens :refer [access-tokens-page]] [app.main.ui.settings.change-email] @@ -20,7 +19,6 @@ [app.main.ui.settings.password :refer [password-page]] [app.main.ui.settings.profile :refer [profile-page]] [app.main.ui.settings.sidebar :refer [sidebar]] - [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [rumext.v2 :as mf])) @@ -28,21 +26,13 @@ (mf/defc header {::mf/wrap [mf/memo]} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:header {:class (stl/css :dashboard-header)} - [:div {:class (stl/css :dashboard-title)} - [:h1 {:data-test "account-title"} (tr "dashboard.your-account-title")]]] - - ;; OLD - [:header.dashboard-header - [:div.dashboard-title - [:h1 {:data-test "account-title"} (tr "dashboard.your-account-title")]]]))) + [:header {:class (stl/css :dashboard-header)} + [:div {:class (stl/css :dashboard-title)} + [:h1 {:data-test "account-title"} (tr "dashboard.your-account-title")]]]) (mf/defc settings [{:keys [route] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - section (get-in route [:data :name]) + (let [section (get-in route [:data :name]) profile (mf/deref refs/profile) locale (mf/deref i18n/locale)] @@ -52,53 +42,26 @@ #(when (nil? profile) (st/emit! (rt/nav :auth-login)))) - (if new-css-system - [:section {:class (stl/css :dashboard-layout-refactor :dashboard)} - [:& sidebar {:profile profile - :locale locale - :section section}] + [:section {:class (stl/css :dashboard-layout-refactor :dashboard)} + [:& sidebar {:profile profile + :locale locale + :section section}] - [:div {:class (stl/css :dashboard-content)} - [:& header] - [:section {:class (stl/css :dashboard-container)} - (case section - :settings-profile - [:& profile-page {:locale locale}] + [:div {:class (stl/css :dashboard-content)} + [:& header] + [:section {:class (stl/css :dashboard-container)} + (case section + :settings-profile + [:& profile-page {:locale locale}] - :settings-feedback - [:& feedback-page] + :settings-feedback + [:& feedback-page] - :settings-password - [:& password-page {:locale locale}] + :settings-password + [:& password-page {:locale locale}] - :settings-options - [:& options-page {:locale locale}] + :settings-options + [:& options-page {:locale locale}] - :settings-access-tokens - [:& access-tokens-page])]]] - - ;; OLD - [:section {:class (dom/classnames :dashboard-layout (not new-css-system) - :dashboard-layout-refactor new-css-system)} - [:& sidebar {:profile profile - :locale locale - :section section}] - - [:div.dashboard-content - [:& header] - [:section.dashboard-container - (case section - :settings-profile - [:& profile-page {:locale locale}] - - :settings-feedback - [:& feedback-page] - - :settings-password - [:& password-page {:locale locale}] - - :settings-options - [:& options-page {:locale locale}] - - :settings-access-tokens - [:& access-tokens-page])]]]))) + :settings-access-tokens + [:& access-tokens-page])]]])) diff --git a/frontend/src/app/main/ui/settings/access_tokens.cljs b/frontend/src/app/main/ui/settings/access_tokens.cljs index 5ca78226b8..cb71674f34 100644 --- a/frontend/src/app/main/ui/settings/access_tokens.cljs +++ b/frontend/src/app/main/ui/settings/access_tokens.cljs @@ -137,7 +137,7 @@ :disabled @created? :name :expiration-date}] (when @created? - [:span.token-created-info + [:span {:class (stl/css :token-created-info)} (if (:expires-at created) (tr "dashboard.access-tokens.token-will-expire" (dt/format-date-locale (:expires-at created) {:locale locale})) (tr "dashboard.access-tokens.token-will-not-expire"))])] diff --git a/frontend/src/app/main/ui/settings/access_tokens.scss b/frontend/src/app/main/ui/settings/access_tokens.scss index 84b46fd7cf..50bdef0af3 100644 --- a/frontend/src/app/main/ui/settings/access_tokens.scss +++ b/frontend/src/app/main/ui/settings/access_tokens.scss @@ -12,6 +12,11 @@ font-size: $fs-16; margin-top: $s-20; width: $s-800; + svg { + width: $s-12; + height: $s-12; + fill: $df-primary; + } } .table-header { @@ -95,12 +100,6 @@ } } -svg { - width: $s-12; - height: $s-12; - fill: $df-primary; -} - .dashboard-access-tokens { display: flex; flex-direction: column; @@ -171,75 +170,85 @@ svg { .modal-overlay { @extend .modal-overlay-base; - .modal-container { - @extend .modal-container-base; - min-width: $s-408; - border: $s-1 solid var(--modal-border-color); - .modal-header { - margin-bottom: $s-24; - .modal-title { - @include tabTitleTipography; - color: var(--modal-title-foreground-color); - } - .modal-close-btn { - @extend .modal-close-btn-base; - } - } +} - .modal-content { - @include flexColumn; - gap: $s-24; - @include titleTipography; - margin-bottom: $s-24; +.modal-container { + @extend .modal-container-base; + min-width: $s-408; + border: $s-1 solid var(--modal-border-color); +} - .fields-row { - @include flexColumn; - .select-title { - @include titleTipography; - color: var(--modal-title-foreground-color); - } - .custon-input-wrapper { - @include flexRow; - border-radius: $br-8; - height: $s-32; - background-color: var(--input-background-color); - } - .custom-input-token { - @extend .input-element; - margin: 0; - flex-grow: 1; - &:focus { - outline: none; - border: $s-1 solid var(--input-border-color-active); - } - } - .token-value { - @include textEllipsis; - @include titleTipography; - flex-grow: 1; - } - .copy-btn { - @include flexCenter; - @extend .button-secondary; - height: $s-28; - width: $s-28; - svg { - @extend .button-icon-small; - } - } - } - } - - .modal-footer { - .action-buttons { - @extend .modal-action-btns; - button { - @extend .modal-accept-btn; - } - .cancel-button { - @extend .modal-cancel-btn; - } - } - } +.modal-header { + margin-bottom: $s-24; + .modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); + } + .modal-close-btn { + @extend .modal-close-btn-base; } } + +.modal-content { + @include flexColumn; + gap: $s-24; + @include titleTipography; + margin-bottom: $s-24; +} + +.fields-row { + @include flexColumn; +} + +.select-title { + @include titleTipography; + color: var(--modal-title-foreground-color); +} + +.custon-input-wrapper { + @include flexRow; + border-radius: $br-8; + height: $s-32; + background-color: var(--input-background-color); +} + +.custom-input-token { + @extend .input-element; + margin: 0; + flex-grow: 1; + &:focus { + outline: none; + border: $s-1 solid var(--input-border-color-active); + } +} + +.token-value { + @include textEllipsis; + @include titleTipography; + flex-grow: 1; +} + +.copy-btn { + @include flexCenter; + @extend .button-secondary; + height: $s-28; + width: $s-28; + svg { + @extend .button-icon-small; + } +} + +.token-created-info { + color: var(--modal-text-foreground-color); +} + +.action-buttons { + @extend .modal-action-btns; + button { + @extend .modal-accept-btn; + } +} + +.cancel-button { + @extend .modal-cancel-btn; +} diff --git a/frontend/src/app/main/ui/settings/feedback.cljs b/frontend/src/app/main/ui/settings/feedback.cljs index 46bbc1e1bf..82daf3c5b4 100644 --- a/frontend/src/app/main/ui/settings/feedback.cljs +++ b/frontend/src/app/main/ui/settings/feedback.cljs @@ -14,7 +14,6 @@ [app.main.repo :as rp] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [beicon.v2.core :as rx] @@ -29,8 +28,7 @@ (mf/defc feedback-form [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - profile (mf/deref refs/profile) + (let [profile (mf/deref refs/profile) form (fm/use-form :spec ::feedback-form :validators [(fm/validate-length :subject fm/max-length-allowed (tr "auth.name.too-long")) (fm/validate-not-empty :subject (tr "auth.name.not-all-space"))]) @@ -62,101 +60,54 @@ (->> (rp/cmd! :send-user-feedback data) (rx/subs! on-succes on-error)))))] - (if new-css-system - [:& fm/form {:class (stl/css :feedback-form) - :on-submit on-submit - :form form} + [:& fm/form {:class (stl/css :feedback-form) + :on-submit on-submit + :form form} ;; --- Feedback section - [:h2 {:class (stl/css :field-title)} (tr "feedback.title")] - [:p {:class (stl/css :field-text)} (tr "feedback.subtitle")] + [:h2 {:class (stl/css :field-title)} (tr "feedback.title")] + [:p {:class (stl/css :field-text)} (tr "feedback.subtitle")] - [:div {:class (stl/css :fields-row)} - [:& fm/input {:label (tr "feedback.subject") - :name :subject - :show-success? true}]] - [:div {:class (stl/css :fields-row :description)} - [:& fm/textarea - {:label (tr "feedback.description") - :name :content - :rows 5}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input {:label (tr "feedback.subject") + :name :subject + :show-success? true}]] + [:div {:class (stl/css :fields-row :description)} + [:& fm/textarea + {:label (tr "feedback.description") + :name :content + :rows 5}]] - [:> fm/submit-button* - {:label (if @loading (tr "labels.sending") (tr "labels.send")) - :disabled @loading}] + [:> fm/submit-button* + {:label (if @loading (tr "labels.sending") (tr "labels.send")) + :disabled @loading}] - [:hr] + [:hr] - [:h2 {:class (stl/css :field-title)} (tr "feedback.discourse-title")] - [:p {:class (stl/css :field-text)} (tr "feedback.discourse-subtitle1")] + [:h2 {:class (stl/css :field-title)} (tr "feedback.discourse-title")] + [:p {:class (stl/css :field-text)} (tr "feedback.discourse-subtitle1")] - [:a - {:class (stl/css :btn-secondary :btn-large) - :href "https://community.penpot.app" - :target "_blank"} - (tr "feedback.discourse-go-to")] - [:hr] + [:a + {:class (stl/css :btn-secondary :btn-large) + :href "https://community.penpot.app" + :target "_blank"} + (tr "feedback.discourse-go-to")] + [:hr] - [:h2 {:class (stl/css :field-title)} (tr "feedback.twitter-title")] - [:p {:class (stl/css :field-text)} (tr "feedback.twitter-subtitle1")] + [:h2 {:class (stl/css :field-title)} (tr "feedback.twitter-title")] + [:p {:class (stl/css :field-text)} (tr "feedback.twitter-subtitle1")] - [:a - {:class (stl/css :btn-secondary :btn-large) - :href "https://twitter.com/penpotapp" - :target "_blank"} - (tr "feedback.twitter-go-to")]] - - ;; OLD - [:& fm/form {:class "feedback-form" - :on-submit on-submit - :form form} - - ;; --- Feedback section - [:h2.field-title (tr "feedback.title")] - [:p.field-text (tr "feedback.subtitle")] - - [:div.fields-row - [:& fm/input {:label (tr "feedback.subject") - :name :subject}]] - [:div.fields-row - [:& fm/textarea - {:label (tr "feedback.description") - :name :content - :rows 5}]] - - [:> fm/submit-button* - {:label (if @loading (tr "labels.sending") (tr "labels.send")) - :disabled @loading}] - - [:hr] - - [:h2.field-title (tr "feedback.discourse-title")] - [:p.field-text (tr "feedback.discourse-subtitle1")] - - [:a.btn-secondary.btn-large - {:href "https://community.penpot.app" :target "_blank"} - (tr "feedback.discourse-go-to")] - [:hr] - - [:h2.field-title (tr "feedback.twitter-title")] - [:p.field-text (tr "feedback.twitter-subtitle1")] - - [:a.btn-secondary.btn-large - {:href "https://twitter.com/penpotapp" :target "_blank"} - (tr "feedback.twitter-go-to")]]))) + [:a + {:class (stl/css :btn-secondary :btn-large) + :href "https://twitter.com/penpotapp" + :target "_blank"} + (tr "feedback.twitter-go-to")]])) (mf/defc feedback-page [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (mf/use-effect - #(dom/set-html-title (tr "title.settings.feedback"))) + (mf/use-effect + #(dom/set-html-title (tr "title.settings.feedback"))) - (if new-css-system - [:div {:class (stl/css :dashboard-settings)} - [:div {:class (stl/css :form-container)} - [:& feedback-form]]] - - ;; OLD - [:div.dashboard-settings - [:div.form-container - [:& feedback-form]]]))) + [:div {:class (stl/css :dashboard-settings)} + [:div {:class (stl/css :form-container)} + [:& feedback-form]]]) diff --git a/frontend/src/app/main/ui/settings/options.cljs b/frontend/src/app/main/ui/settings/options.cljs index 2ec2476590..34b539a84f 100644 --- a/frontend/src/app/main/ui/settings/options.cljs +++ b/frontend/src/app/main/ui/settings/options.cljs @@ -13,7 +13,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cljs.spec.alpha :as s] @@ -38,78 +37,49 @@ (mf/defc options-form {::mf/wrap-props false} [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - profile (mf/deref refs/profile) + (let [profile (mf/deref refs/profile) initial (mf/with-memo [profile] (update profile :lang #(or % ""))) form (fm/use-form :spec ::options-form :initial initial)] - (if new-css-system - [:& fm/form {:class (stl/css :options-form) - :on-submit on-submit - :form form} + [:& fm/form {:class (stl/css :options-form) + :on-submit on-submit + :form form} - [:h3 (tr "labels.language")] + [:h3 (tr "labels.language")] - [:div {:class (stl/css :fields-row)} - [:& fm/select {:options (into [{:label "Auto (browser)" :value ""}] - i18n/supported-locales) - :label (tr "dashboard.select-ui-language") - :default "" - :name :lang - :data-test "setting-lang"}]] + [:div {:class (stl/css :fields-row)} + [:& fm/select {:options (into [{:label "Auto (browser)" :value ""}] + i18n/supported-locales) + :label (tr "dashboard.select-ui-language") + :default "" + :name :lang + :data-test "setting-lang"}]] - [:h3 (tr "dashboard.theme-change")] - [:div {:class (stl/css :fields-row)} - [:& fm/select {:label (tr "dashboard.select-ui-theme") - :name :theme - :default "default" - :options [{:label "Penpot Dark (default)" :value "default"} - {:label "Penpot Light" :value "light"}] - :data-test "setting-theme"}]] + [:h3 (tr "dashboard.theme-change")] + [:div {:class (stl/css :fields-row)} + [:& fm/select {:label (tr "dashboard.select-ui-theme") + :name :theme + :default "default" + :options [{:label "Penpot Dark (default)" :value "default"} + {:label "Penpot Light" :value "light"}] + :data-test "setting-theme"}]] - [:> fm/submit-button* - {:label (tr "dashboard.update-settings") - :data-test "submit-lang-change" - :class (stl/css :btn-primary)}]] - - ;; OLD - [:& fm/form {:class "options-form" - :on-submit on-submit - :form form} - - [:h2 (tr "labels.language")] - - [:div.fields-row - [:& fm/select {:options (into [{:label "Auto (browser)" :value ""}] - i18n/supported-locales) - :label (tr "dashboard.select-ui-language") - :default "" - :name :lang - :data-test "setting-lang"}]] - - [:> fm/submit-button* - {:label (tr "dashboard.update-settings") - :data-test "submit-lang-change"}]]))) + [:> fm/submit-button* + {:label (tr "dashboard.update-settings") + :data-test "submit-lang-change" + :class (stl/css :btn-primary)}]])) ;; --- Password Page (mf/defc options-page [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (mf/use-effect - #(dom/set-html-title (tr "title.settings.options"))) + (mf/use-effect + #(dom/set-html-title (tr "title.settings.options"))) - (if new-css-system - [:div {:class (stl/css :dashboard-settings)} - [:div {:class (stl/css :form-container) :data-test "settings-form"} - [:h2 (tr "labels.settings")] - [:& options-form {}]]] - - ;; OLD - [:div.dashboard-settings - [:div.form-container - {:data-test "settings-form"} - [:& options-form {}]]]))) + [:div {:class (stl/css :dashboard-settings)} + [:div {:class (stl/css :form-container) :data-test "settings-form"} + [:h2 (tr "labels.settings")] + [:& options-form {}]]]) diff --git a/frontend/src/app/main/ui/settings/password.cljs b/frontend/src/app/main/ui/settings/password.cljs index 0b9b1b5a0a..f96edbc306 100644 --- a/frontend/src/app/main/ui/settings/password.cljs +++ b/frontend/src/app/main/ui/settings/password.cljs @@ -12,7 +12,6 @@ [app.main.data.users :as udu] [app.main.store :as st] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [t tr]] [cljs.spec.alpha :as s] @@ -71,88 +70,51 @@ (mf/defc password-form [{:keys [locale] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - initial (mf/use-memo (constantly {:password-old nil})) + (let [initial (mf/use-memo (constantly {:password-old nil})) form (fm/use-form :spec ::password-form :validators [(fm/validate-not-all-spaces :password-old (tr "auth.password-not-empty")) (fm/validate-not-empty :password-1 (tr "auth.password-not-empty")) (fm/validate-not-empty :password-2 (tr "auth.password-not-empty")) password-equality] :initial initial)] - (if new-css-system - [:& fm/form {:class (stl/css :password-form) - :on-submit on-submit - :form form} + [:& fm/form {:class (stl/css :password-form) + :on-submit on-submit + :form form} - [:div {:class (stl/css :fields-row)} - [:& fm/input - {:type "password" - :name :password-old - :auto-focus? true - :label (t locale "labels.old-password")}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input + {:type "password" + :name :password-old + :auto-focus? true + :label (t locale "labels.old-password")}]] - [:div {:class (stl/css :fields-row)} - [:& fm/input - {:type "password" - :name :password-1 - :show-success? true - :label (t locale "labels.new-password")}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input + {:type "password" + :name :password-1 + :show-success? true + :label (t locale "labels.new-password")}]] - [:div {:class (stl/css :fields-row)} - [:& fm/input - {:type "password" - :name :password-2 - :show-success? true - :label (t locale "labels.confirm-password")}]] + [:div {:class (stl/css :fields-row)} + [:& fm/input + {:type "password" + :name :password-2 + :show-success? true + :label (t locale "labels.confirm-password")}]] - [:> fm/submit-button* - {:label (t locale "dashboard.update-settings") - :data-test "submit-password" - :class (stl/css :update-btn)}]] - - ;; OLD - [:& fm/form {:class "password-form" - :on-submit on-submit - :form form} - [:h2 (t locale "dashboard.password-change")] - [:div.fields-row - [:& fm/input - {:type "password" - :name :password-old - :auto-focus? true - :label (t locale "labels.old-password")}]] - - [:div.fields-row - [:& fm/input - {:type "password" - :name :password-1 - :label (t locale "labels.new-password")}]] - - [:div.fields-row - [:& fm/input - {:type "password" - :name :password-2 - :label (t locale "labels.confirm-password")}]] - - [:> fm/submit-button* - {:label (t locale "dashboard.update-settings") - :data-test "submit-password"}]]))) + [:> fm/submit-button* + {:label (t locale "dashboard.update-settings") + :data-test "submit-password" + :class (stl/css :update-btn)}]])) ;; --- Password Page (mf/defc password-page [{:keys [locale]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (mf/use-effect - #(dom/set-html-title (tr "title.settings.password"))) + (mf/use-effect + #(dom/set-html-title (tr "title.settings.password"))) - (if new-css-system - [:section {:class (stl/css :dashboard-settings)} - [:div {:class (stl/css :form-container)} - [:h2 (t locale "dashboard.password-change")] - [:& password-form {:locale locale}]]] - - ;; old - [:section.dashboard-settings.form-container - [:div.form-container - [:& password-form {:locale locale}]]]))) + [:section {:class (stl/css :dashboard-settings)} + [:div {:class (stl/css :form-container)} + [:h2 (t locale "dashboard.password-change")] + [:& password-form {:locale locale}]]]) diff --git a/frontend/src/app/main/ui/settings/profile.cljs b/frontend/src/app/main/ui/settings/profile.cljs index b946b68462..c3bd7fe5bd 100644 --- a/frontend/src/app/main/ui/settings/profile.cljs +++ b/frontend/src/app/main/ui/settings/profile.cljs @@ -16,8 +16,6 @@ [app.main.store :as st] [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.forms :as fm] - [app.main.ui.context :as ctx] - [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cljs.spec.alpha :as s] @@ -43,9 +41,7 @@ (mf/defc profile-form [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - - profile (mf/deref refs/profile) + (let [profile (mf/deref refs/profile) form (fm/use-form :spec ::profile-form :initial profile :validators [(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long")) @@ -59,78 +55,43 @@ (mf/use-callback #(modal/show! :delete-account {}))] - (if new-css-system - [:& fm/form {:on-submit on-submit - :form form - :class (stl/css :profile-form)} - [:div {:class (stl/css :fields-row)} - [:& fm/input - {:type "text" - :name :fullname - :label (tr "dashboard.your-name")}]] + [:& fm/form {:on-submit on-submit + :form form + :class (stl/css :profile-form)} + [:div {:class (stl/css :fields-row)} + [:& fm/input + {:type "text" + :name :fullname + :label (tr "dashboard.your-name")}]] - [:div {:class (stl/css :fields-row) - :on-click handle-show-change-email} - [:& fm/input - {:type "email" - :name :email - :disabled true - :label (tr "dashboard.your-email")}] + [:div {:class (stl/css :fields-row) + :on-click handle-show-change-email} + [:& fm/input + {:type "email" + :name :email + :disabled true + :label (tr "dashboard.your-email")}] - [:div {:class (stl/css :options)} - [:div.change-email - [:a {:on-click handle-show-change-email} - (tr "dashboard.change-email")]]]] + [:div {:class (stl/css :options)} + [:div.change-email + [:a {:on-click handle-show-change-email} + (tr "dashboard.change-email")]]]] - [:> fm/submit-button* - {:label (tr "dashboard.save-settings") - :disabled (empty? (:touched @form)) - :className (stl/css :btn-primary)}] + [:> fm/submit-button* + {:label (tr "dashboard.save-settings") + :disabled (empty? (:touched @form)) + :className (stl/css :btn-primary)}] - [:div {:class (stl/css :links)} - [:div {:class (stl/css :link-item)} - [:a {:on-click handle-show-delete-account - :data-test "remove-acount-btn"} - (tr "dashboard.remove-account")]]]] - - ;; OLD - [:& fm/form {:on-submit on-submit - :form form - :class "profile-form"} - [:div.fields-row - [:& fm/input - {:type "text" - :name :fullname - :label (tr "dashboard.your-name")}]] - - [:div.fields-row - [:& fm/input - {:type "email" - :name :email - :disabled true - :help-icon i/at - :label (tr "dashboard.your-email")}] - - [:div.options - [:div.change-email - [:a {:on-click #(modal/show! :change-email {})} - (tr "dashboard.change-email")]]]] - - [:> fm/submit-button* - {:label (tr "dashboard.save-settings") - :disabled (empty? (:touched @form))}] - - [:div.links - [:div.link-item - [:a {:on-click #(modal/show! :delete-account {}) - :data-test "remove-acount-btn"} - (tr "dashboard.remove-account")]]]]))) + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-item)} + [:a {:on-click handle-show-delete-account + :data-test "remove-acount-btn"} + (tr "dashboard.remove-account")]]]])) ;; --- Profile Photo Form (mf/defc profile-photo-form [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - file-input (mf/use-ref nil) + (let [file-input (mf/use-ref nil) profile (mf/deref refs/profile) photo (cf/resolve-profile-photo-url profile) on-image-click #(dom/click (mf/ref-val file-input)) @@ -139,44 +100,25 @@ (fn [file] (st/emit! (du/update-photo file)))] - (if new-css-system - [:form {:class (stl/css :avatar-form)} - [:div {:class (stl/css :image-change-field)} - [:span {:class (stl/css :update-overlay) - :on-click on-image-click} (tr "labels.update")] - [:img {:src photo}] - [:& file-uploader {:accept "image/jpeg,image/png" - :multi false - :ref file-input - :on-selected on-file-selected - :data-test "profile-image-input"}]]] - ;; OLD - [:form.avatar-form - [:div.image-change-field - [:span.update-overlay {:on-click on-image-click} (tr "labels.update")] - [:img {:src photo}] - [:& file-uploader {:accept "image/jpeg,image/png" - :multi false - :ref file-input - :on-selected on-file-selected - :data-test "profile-image-input"}]]]))) + [:form {:class (stl/css :avatar-form)} + [:div {:class (stl/css :image-change-field)} + [:span {:class (stl/css :update-overlay) + :on-click on-image-click} (tr "labels.update")] + [:img {:src photo}] + [:& file-uploader {:accept "image/jpeg,image/png" + :multi false + :ref file-input + :on-selected on-file-selected + :data-test "profile-image-input"}]]])) ;; --- Profile Page (mf/defc profile-page [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (mf/with-effect [] - (dom/set-html-title (tr "title.settings.profile"))) - (if new-css-system - [:div {:class (stl/css :dashboard-settings)} - [:div {:class (stl/css :form-container)} - [:h2 (tr "labels.profile")] - [:& profile-photo-form] - [:& profile-form]]] - - ;; OLD - [:div.dashboard-settings - [:div.form-container.two-columns - [:& profile-photo-form] - [:& profile-form]]]))) + (mf/with-effect [] + (dom/set-html-title (tr "title.settings.profile"))) + [:div {:class (stl/css :dashboard-settings)} + [:div {:class (stl/css :form-container)} + [:h2 (tr "labels.profile")] + [:& profile-photo-form] + [:& profile-form]]]) diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs index 5d3fc8c8b7..c82664b115 100644 --- a/frontend/src/app/main/ui/settings/sidebar.cljs +++ b/frontend/src/app/main/ui/settings/sidebar.cljs @@ -12,7 +12,6 @@ [app.main.data.modal :as modal] [app.main.data.users :as du] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.dashboard.sidebar :refer [profile-section]] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] @@ -23,8 +22,7 @@ (mf/defc sidebar-content [{:keys [profile section] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - profile? (= section :settings-profile) + (let [profile? (= section :settings-profile) password? (= section :settings-password) options? (= section :settings-options) feedback? (= section :settings-feedback) @@ -69,107 +67,52 @@ (st/emit! (modal/show {:type :onboarding})) (st/emit! (modal/show {:type :release-notes :version version}))))))] - (if new-css-system - [:div {:class (stl/css :sidebar-content)} - [:div {:class (stl/css :sidebar-content-section)} - [:div {:class (stl/css :back-to-dashboard) - :on-click go-dashboard} - [:span {:class (stl/css :icon)} i/arrow-down] - [:span {:class (stl/css :text)} (tr "labels.dashboard")]]] + [:div {:class (stl/css :sidebar-content)} + [:div {:class (stl/css :sidebar-content-section)} + [:div {:class (stl/css :back-to-dashboard) + :on-click go-dashboard} + [:span {:class (stl/css :icon)} i/arrow-down] + [:span {:class (stl/css :text)} (tr "labels.dashboard")]]] + [:hr] + + [:div {:class (stl/css :sidebar-content-section)} + [:ul {:class (stl/css :sidebar-nav :no-overflow)} + [:li {:class (when profile? (stl/css :current)) + :on-click go-settings-profile} + [:span {:class (stl/css :element-title)} (tr "labels.profile")]] + + [:li {:class (when password? (stl/css :current)) + :on-click go-settings-password} + [:span {:class (stl/css :element-title)} (tr "labels.password")]] + + [:li {:class (when options? (stl/css :current)) + :on-click go-settings-options + :data-test "settings-profile"} + [:span {:class (stl/css :element-title)} (tr "labels.settings")]] + + (when (contains? cf/flags :access-tokens) + [:li {:class (when access-tokens? (stl/css :current)) + :on-click go-settings-access-tokens + :data-test "settings-access-tokens"} + [:span {:class (stl/css :element-title)} (tr "labels.access-tokens")]]) + [:hr] - [:div {:class (stl/css :sidebar-content-section)} - [:ul {:class (stl/css :sidebar-nav :no-overflow)} - [:li {:class (when profile? (stl/css :current)) - :on-click go-settings-profile} - [:span {:class (stl/css :element-title)} (tr "labels.profile")]] + [:li {:on-click show-release-notes :data-test "release-notes"} + [:span {:class (stl/css :element-title)} (tr "labels.release-notes")]] - [:li {:class (when password? (stl/css :current)) - :on-click go-settings-password} - [:span {:class (stl/css :element-title)} (tr "labels.password")]] - - [:li {:class (when options? (stl/css :current)) - :on-click go-settings-options - :data-test "settings-profile"} - [:span {:class (stl/css :element-title)} (tr "labels.settings")]] - - (when (contains? cf/flags :access-tokens) - [:li {:class (when access-tokens? (stl/css :current)) - :on-click go-settings-access-tokens - :data-test "settings-access-tokens"} - [:span {:class (stl/css :element-title)} (tr "labels.access-tokens")]]) - - [:hr] - - [:li {:on-click show-release-notes :data-test "release-notes"} - [:span {:class (stl/css :element-title)} (tr "labels.release-notes")]] - - (when (contains? cf/flags :user-feedback) - [:li {:class (when feedback? (stl/css :current)) - :on-click go-settings-feedback} - i/msg-info - [:span {:class (stl/css :element-title)} (tr "labels.give-feedback")]])]]] - - ;; OLD - [:div.sidebar-content - [:div.sidebar-content-section - [:div.back-to-dashboard {:on-click go-dashboard} - [:span.icon i/arrow-down] - [:span.text (tr "labels.dashboard")]]] - [:hr] - - [:div.sidebar-content-section - [:ul.sidebar-nav.no-overflow - [:li {:class (when profile? "current") - :on-click go-settings-profile} - i/user - [:span.element-title (tr "labels.profile")]] - - [:li {:class (when password? "current") - :on-click go-settings-password} - i/lock - [:span.element-title (tr "labels.password")]] - - [:li {:class (when options? "current") - :on-click go-settings-options - :data-test "settings-profile"} - i/tree - [:span.element-title (tr "labels.settings")]] - - (when (contains? cf/flags :access-tokens) - [:li {:class (when access-tokens? "current") - :on-click go-settings-access-tokens - :data-test "settings-access-tokens"} - i/icon-key - [:span.element-title (tr "labels.access-tokens")]]) - - [:hr] - - [:li {:on-click show-release-notes :data-test "release-notes"} - i/pencil - [:span.element-title (tr "labels.release-notes")]] - - (when (contains? cf/flags :user-feedback) - [:li {:class (when feedback? "current") - :on-click go-settings-feedback} - i/msg-info - [:span.element-title (tr "labels.give-feedback")]])]]]))) + (when (contains? cf/flags :user-feedback) + [:li {:class (when feedback? (stl/css :current)) + :on-click go-settings-feedback} + i/msg-info + [:span {:class (stl/css :element-title)} (tr "labels.give-feedback")]])]]])) (mf/defc sidebar {::mf/wrap [mf/memo]} [{:keys [profile locale section]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :dashboard-sidebar :settings)} - [:& sidebar-content {:profile profile - :section section}] - [:& profile-section {:profile profile - :locale locale}]] - - ;; OLD - [:div.dashboard-sidebar.settings - [:& sidebar-content {:profile profile - :section section}] - [:& profile-section {:profile profile - :locale locale}]]))) + [:div {:class (stl/css :dashboard-sidebar :settings)} + [:& sidebar-content {:profile profile + :section section}] + [:& profile-section {:profile profile + :locale locale}]]) diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs index 916d2fa38d..04ae734912 100644 --- a/frontend/src/app/main/ui/static.cljs +++ b/frontend/src/app/main/ui/static.cljs @@ -20,112 +20,64 @@ (mf/defc static-header {::mf/wrap-props false} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - children (obj/get props "children") + (let [children (obj/get props "children") on-click (mf/use-callback #(set! (.-href globals/location) "/"))] - (if new-css-system - [:section {:class (stl/css :exception-layout)} - [:button - {:class (stl/css :exception-header) - :on-click on-click} - i/logo-icon] - [:div {:class (stl/css :deco-before)} i/logo-error-screen] + [:section {:class (stl/css :exception-layout)} + [:button + {:class (stl/css :exception-header) + :on-click on-click} + i/logo-icon] + [:div {:class (stl/css :deco-before)} i/logo-error-screen] - [:div {:class (stl/css :exception-content)} - [:div {:class (stl/css :container)} children]] + [:div {:class (stl/css :exception-content)} + [:div {:class (stl/css :container)} children]] - [:div {:class (stl/css :deco-after)} i/logo-error-screen]] - [:section.exception-layout - [:div.exception-header - {:on-click on-click} - i/logo] - [:div.exception-content - [:div.container children]]]))) + [:div {:class (stl/css :deco-after)} i/logo-error-screen]])) (mf/defc invalid-token [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:> static-header {} - [:div {:class (stl/css :main-message)} (tr "errors.invite-invalid")] - [:div {:class (stl/css :desc-message)} (tr "errors.invite-invalid.info")]] - - [:> static-header {} - [:div.image i/unchain] - [:div.main-message (tr "errors.invite-invalid")] - [:div.desc-message (tr "errors.invite-invalid.info")]]))) + [:> static-header {} + [:div {:class (stl/css :main-message)} (tr "errors.invite-invalid")] + [:div {:class (stl/css :desc-message)} (tr "errors.invite-invalid.info")]]) (mf/defc not-found [] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:> static-header {} - [:div {:class (stl/css :main-message)} (tr "labels.not-found.main-message")] - [:div {:class (stl/css :desc-message)} (tr "labels.not-found.desc-message")]] - - [:> static-header {} - [:div.image i/icon-empty] - [:div.main-message (tr "labels.not-found.main-message")] - [:div.desc-message (tr "labels.not-found.desc-message")]]))) + [:> static-header {} + [:div {:class (stl/css :main-message)} (tr "labels.not-found.main-message")] + [:div {:class (stl/css :desc-message)} (tr "labels.not-found.desc-message")]]) (mf/defc bad-gateway [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - handle-retry + (let [handle-retry (mf/use-callback (fn [] (st/emit! (rt/assign-exception nil))))] - (if new-css-system - [:> static-header {} - [:div {:class (stl/css :main-message)} (tr "labels.bad-gateway.main-message")] - [:div {:class (stl/css :desc-message)} (tr "labels.bad-gateway.desc-message")] - [:div {:class (stl/css :sign-info)} - [:button {:on-click handle-retry} (tr "labels.retry")]]] - - [:> static-header {} - [:div.image i/icon-empty] - [:div.main-message (tr "labels.bad-gateway.main-message")] - [:div.desc-message (tr "labels.bad-gateway.desc-message")] - [:div.sign-info - [:a.btn-primary.btn-small {:on-click handle-retry} (tr "labels.retry")]]]))) + [:> static-header {} + [:div {:class (stl/css :main-message)} (tr "labels.bad-gateway.main-message")] + [:div {:class (stl/css :desc-message)} (tr "labels.bad-gateway.desc-message")] + [:div {:class (stl/css :sign-info)} + [:button {:on-click handle-retry} (tr "labels.retry")]]])) (mf/defc service-unavailable [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - handle-retry + (let [handle-retry (mf/use-callback (fn [] (st/emit! (rt/assign-exception nil))))] - (if new-css-system - [:> static-header {} - [:div {:class (stl/css :main-message)} (tr "labels.service-unavailable.main-message")] - [:div {:class (stl/css :desc-message)} (tr "labels.service-unavailable.desc-message")] - [:div {:class (stl/css :sign-info)} - [:button {:on-click handle-retry} (tr "labels.retry")]]] - - [:> static-header {} - [:div.main-message (tr "labels.service-unavailable.main-message")] - [:div.desc-message (tr "labels.service-unavailable.desc-message")] - [:div.sign-info - [:a.btn-primary.btn-small {:on-click handle-retry} (tr "labels.retry")]]]))) + [:> static-header {} + [:div {:class (stl/css :main-message)} (tr "labels.service-unavailable.main-message")] + [:div {:class (stl/css :desc-message)} (tr "labels.service-unavailable.desc-message")] + [:div {:class (stl/css :sign-info)} + [:button {:on-click handle-retry} (tr "labels.retry")]]])) (mf/defc internal-error [] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - handle-retry + (let [handle-retry (mf/use-callback (fn [] (st/emit! (rt/assign-exception nil))))] - (if new-css-system - [:> static-header {} - [:div {:class (stl/css :main-message)} (tr "labels.internal-error.main-message")] - [:div {:class (stl/css :desc-message)} (tr "labels.internal-error.desc-message")] - [:div {:class (stl/css :sign-info)} - [:button {:on-click handle-retry} (tr "labels.retry")]]] - - [:> static-header {} - [:div.image i/icon-empty] - [:div.main-message (tr "labels.internal-error.main-message")] - [:div.desc-message (tr "labels.internal-error.desc-message")] - [:div.sign-info - [:a.btn-primary.btn-small {:on-click handle-retry} (tr "labels.retry")]]]))) + [:> static-header {} + [:div {:class (stl/css :main-message)} (tr "labels.internal-error.main-message")] + [:div {:class (stl/css :desc-message)} (tr "labels.internal-error.desc-message")] + [:div {:class (stl/css :sign-info)} + [:button {:on-click handle-retry} (tr "labels.retry")]]])) (mf/defc exception-page [{:keys [data] :as props}] diff --git a/frontend/src/app/main/ui/viewer/share_link.scss b/frontend/src/app/main/ui/viewer/share_link.scss index dc0fbc7b4e..da9ce16d71 100644 --- a/frontend/src/app/main/ui/viewer/share_link.scss +++ b/frontend/src/app/main/ui/viewer/share_link.scss @@ -48,6 +48,7 @@ } .hint { flex-grow: 1; + color: var(--modal-text-foreground-color); } .custon-input-wrapper { @include flexRow; @@ -68,6 +69,7 @@ border: $s-1 solid var(--input-border-color-active); } } + .copy-button { @extend .button-secondary; @include flexRow; @@ -93,9 +95,11 @@ .button-active { @extend .modal-accept-btn; } + .button-cancel { @extend .modal-cancel-btn; } + .button-danger { @extend .modal-danger-btn; } @@ -126,12 +130,20 @@ transform: rotate(90deg); } } + .view-mode, .access-mode, .inspect-mode { display: flex; width: 100%; } + +.view-mode { + max-height: $s-248; + overflow: hidden auto; + scrollbar-gutter: stable; +} + .subtitle { color: var(--modal-text-foreground-color); display: flex; diff --git a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs index 531b67ccbf..53fb08dfd0 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs @@ -10,7 +10,6 @@ [app.common.colors :as cc] [app.common.data :as d] [app.common.math :as mth] - [app.main.ui.context :as ctx] [app.util.dom :as dom] [rumext.v2 :as mf])) @@ -29,8 +28,7 @@ (* (/ val 255) 100)) (mf/defc color-inputs [{:keys [type color disable-opacity on-change]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - {red :r green :g blue :b + (let [{red :r green :g blue :b hue :h saturation :s value :v hex :hex alpha :alpha} color @@ -115,133 +113,52 @@ property-val)] (dom/set-value! node new-val)))))))) - (if new-css-system - [:div {:class (stl/css-case :color-values true - :disable-opacity disable-opacity)} + [:div {:class (stl/css-case :color-values true + :disable-opacity disable-opacity)} - [:div {:class (stl/css :colors-row)} - (if (= type :rgb) - [:* - [:div {:class (stl/css :input-wrapper)} - [:span {:class (stl/css :input-label)} "R"] - [:input {:id "red-value" - :ref (:r refs) - :type "number" - :min 0 - :max 255 - :default-value red - :on-change (on-change-property :r 255)}]] - [:div {:class (stl/css :input-wrapper)} - [:span {:class (stl/css :input-label)} "G"] - [:input {:id "green-value" - :ref (:g refs) - :type "number" - :min 0 - :max 255 - :default-value green - :on-change (on-change-property :g 255)}]] - [:div {:class (stl/css :input-wrapper)} - [:span {:class (stl/css :input-label)} "B"] - [:input {:id "blue-value" - :ref (:b refs) - :type "number" - :min 0 - :max 255 - :default-value blue - :on-change (on-change-property :b 255)}]]] - - [:* - [:div {:class (stl/css :input-wrapper)} - [:span {:class (stl/css :input-label)} "H"] - [:input {:id "hue-value" - :ref (:h refs) - :type "number" - :min 0 - :max 360 - :default-value hue - :on-change (on-change-property :h 360)}]] - [:div {:class (stl/css :input-wrapper)} - [:span {:class (stl/css :input-label)} "S"] - [:input {:id "saturation-value" - :ref (:s refs) - :type "number" - :min 0 - :max 100 - :step 1 - :default-value saturation - :on-change (on-change-property :s 100)}]] - [:div {:class (stl/css :input-wrapper)} - [:span {:class (stl/css :input-label)} "V"] - [:input {:id "value-value" - :ref (:v refs) - :type "number" - :min 0 - :max 100 - :default-value value - :on-change (on-change-property :v 100)}]]])] - [:div {:class (stl/css :hex-alpha-wrapper)} - [:div {:class (stl/css-case :input-wrapper true - :hex true)} - [:span {:class (stl/css :input-label)} "HEX"] - [:input {:id "hex-value" - :ref (:hex refs) - :default-value hex - :on-change on-change-hex - :on-blur on-blur-hex}]] - (when (not disable-opacity) - [:div {:class (stl/css-case :input-wrapper true)} - [:span {:class (stl/css :input-label)} "A"] - [:input {:id "alpha-value" - :ref (:alpha refs) - :type "number" - :min 0 - :step 1 - :max 100 - :default-value (if (= alpha :multiple) "" alpha) - :on-change on-change-opacity}]])]] - - [:div.color-values - {:class (when disable-opacity "disable-opacity")} - [:input {:id "hex-value" - :ref (:hex refs) - :default-value hex - :on-change on-change-hex - :on-blur on-blur-hex}] - - (if (= type :rgb) - [:* + [:div {:class (stl/css :colors-row)} + (if (= type :rgb) + [:* + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "R"] [:input {:id "red-value" :ref (:r refs) :type "number" :min 0 :max 255 :default-value red - :on-change (on-change-property :r 255)}] - + :on-change (on-change-property :r 255)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "G"] [:input {:id "green-value" :ref (:g refs) :type "number" :min 0 :max 255 :default-value green - :on-change (on-change-property :g 255)}] - + :on-change (on-change-property :g 255)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "B"] [:input {:id "blue-value" :ref (:b refs) :type "number" :min 0 :max 255 :default-value blue - :on-change (on-change-property :b 255)}]] - [:* + :on-change (on-change-property :b 255)}]]] + + [:* + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "H"] [:input {:id "hue-value" :ref (:h refs) :type "number" :min 0 :max 360 :default-value hue - :on-change (on-change-property :h 360)}] - + :on-change (on-change-property :h 360)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "S"] [:input {:id "saturation-value" :ref (:s refs) :type "number" @@ -249,35 +166,33 @@ :max 100 :step 1 :default-value saturation - :on-change (on-change-property :s 100)}] - + :on-change (on-change-property :s 100)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "V"] [:input {:id "value-value" :ref (:v refs) :type "number" :min 0 :max 100 :default-value value - :on-change (on-change-property :v 100)}]]) - - (when (not disable-opacity) - [:input.alpha-value {:id "alpha-value" - :ref (:alpha refs) - :type "number" - :min 0 - :step 1 - :max 100 - :default-value (if (= alpha :multiple) "" alpha) - :on-change on-change-opacity}]) - - [:label.hex-label {:for "hex-value"} "HEX"] - (if (= type :rgb) - [:* - [:label.red-label {:for "red-value"} "R"] - [:label.green-label {:for "green-value"} "G"] - [:label.blue-label {:for "blue-value"} "B"]] - [:* - [:label.red-label {:for "hue-value"} "H"] - [:label.green-label {:for "saturation-value"} "S"] - [:label.blue-label {:for "value-value"} "V"]]) - (when (not disable-opacity) - [:label.alpha-label {:for "alpha-value"} "A"])]))) + :on-change (on-change-property :v 100)}]]])] + [:div {:class (stl/css :hex-alpha-wrapper)} + [:div {:class (stl/css-case :input-wrapper true + :hex true)} + [:span {:class (stl/css :input-label)} "HEX"] + [:input {:id "hex-value" + :ref (:hex refs) + :default-value hex + :on-change on-change-hex + :on-blur on-blur-hex}]] + (when (not disable-opacity) + [:div {:class (stl/css-case :input-wrapper true)} + [:span {:class (stl/css :input-label)} "A"] + [:input {:id "alpha-value" + :ref (:alpha refs) + :type "number" + :min 0 + :step 1 + :max 100 + :default-value (if (= alpha :multiple) "" alpha) + :on-change on-change-opacity}]])]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.scss b/frontend/src/app/main/ui/workspace/sidebar/history.scss index 19d9af08d5..5cebfbcb0d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/history.scss @@ -115,7 +115,7 @@ .history-entry-detail { display: block; padding-top: $s-16; - + color: var(--modal-text-foreground-color); .history-entry-details-list { margin: 0; } diff --git a/frontend/src/app/main/ui/workspace/viewport/comments.cljs b/frontend/src/app/main/ui/workspace/viewport/comments.cljs index f036cbde96..aa59d9e91f 100644 --- a/frontend/src/app/main/ui/workspace/viewport/comments.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/comments.cljs @@ -12,15 +12,13 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.comments :as cmt] - [app.main.ui.context :as ctx] [cuerdas.core :as str] [okulary.core :as l] [rumext.v2 :as mf])) (mf/defc comments-layer [{:keys [vbox vport zoom file-id page-id drawing] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - pos-x (* (- (:x vbox)) zoom) + (let [pos-x (* (- (:x vbox)) zoom) pos-y (* (- (:y vbox)) zoom) profile (mf/deref refs/profile) @@ -57,54 +55,29 @@ (st/emit! (dwcm/initialize-comments file-id)) (fn [] (st/emit! ::dwcm/finalize)))) - (if new-css-system - [:div {:class (stl/css :comments-section)} - [:div - {:class (stl/css :workspace-comments-container) - :style {:width (str (:width vport) "px") - :height (str (:height vport) "px")}} - [:div {:class (stl/css :threads) - :style {:transform (str/format "translate(%spx, %spx)" pos-x pos-y)}} - (for [item threads] - [:& cmt/thread-bubble {:thread item - :zoom zoom - :open? (= (:id item) (:open local)) - :key (:seqn item)}]) + [:div {:class (stl/css :comments-section)} + [:div + {:class (stl/css :workspace-comments-container) + :style {:width (str (:width vport) "px") + :height (str (:height vport) "px")}} + [:div {:class (stl/css :threads) + :style {:transform (str/format "translate(%spx, %spx)" pos-x pos-y)}} + (for [item threads] + [:& cmt/thread-bubble {:thread item + :zoom zoom + :open? (= (:id item) (:open local)) + :key (:seqn item)}]) - (when-let [id (:open local)] - (when-let [thread (get threads-map id)] - [:& cmt/thread-comments {:thread (update-thread-position thread) - :users users - :zoom zoom}])) + (when-let [id (:open local)] + (when-let [thread (get threads-map id)] + [:& cmt/thread-comments {:thread (update-thread-position thread) + :users users + :zoom zoom}])) - (when-let [draft (:comment drawing)] - [:& cmt/draft-thread {:draft draft - :on-cancel on-draft-cancel - :on-submit on-draft-submit - :zoom zoom}])]]] - - ;; OLD - [:div.comments-section - [:div.workspace-comments-container - {:style {:width (str (:width vport) "px") - :height (str (:height vport) "px")}} - [:div.threads {:style {:transform (str/format "translate(%spx, %spx)" pos-x pos-y)}} - (for [item threads] - [:& cmt/thread-bubble {:thread item - :zoom zoom - :open? (= (:id item) (:open local)) - :key (:seqn item)}]) - - (when-let [id (:open local)] - (when-let [thread (get threads-map id)] - [:& cmt/thread-comments {:thread (update-thread-position thread) - :users users - :zoom zoom}])) - - (when-let [draft (:comment drawing)] - [:& cmt/draft-thread {:draft draft - :on-cancel on-draft-cancel - :on-submit on-draft-submit - :zoom zoom}])]]]) + (when-let [draft (:comment drawing)] + [:& cmt/draft-thread {:draft draft + :on-cancel on-draft-cancel + :on-submit on-draft-submit + :zoom zoom}])]]] )) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 7b99e9f618..3d9106d8ab 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -25,7 +25,6 @@ [app.main.data.workspace.shape-layout :as dwsl] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.css-cursors :as cur] [app.main.ui.formats :as fmt] [app.main.ui.hooks :as hooks] @@ -54,28 +53,16 @@ (mf/defc grid-edition-actions {::mf/wrap-props false} [{:keys [shape]}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] - (if new-css-system - [:div {:class (stl/css :grid-actions)} - [:div {:class (stl/css :grid-actions-container)} - [:div {:class (stl/css :grid-actions-title)} - (tr "workspace.layout_grid.editor.title") " " [:span {:stl/css :board-name} (:name shape)]] - [:button {:class (stl/css :locate-btn) - :on-click #(st/emit! (dwge/locate-board (:id shape)))} - (tr "workspace.layout_grid.editor.top-bar.locate")] - [:button {:class (stl/css :done-btn) - :on-click #(st/emit! dw/clear-edition-mode)} - (tr "workspace.layout_grid.editor.top-bar.done")]]] - - [:div.viewport-actions - [:div.viewport-actions-container - [:div.viewport-actions-title - (tr "workspace.layout_grid.editor.title") " " [:span.grid-edit-board-name (:name shape)]] - [:button.btn-secondary {:on-click #(st/emit! (dwge/locate-board (:id shape)))} - (tr "workspace.layout_grid.editor.top-bar.locate")] - [:button.btn-primary {:on-click #(st/emit! dw/clear-edition-mode)} - (tr "workspace.layout_grid.editor.top-bar.done")] - [:button.btn-icon-basic {:on-click #(st/emit! dw/clear-edition-mode)} i/close]]]))) + [:div {:class (stl/css :grid-actions)} + [:div {:class (stl/css :grid-actions-container)} + [:div {:class (stl/css :grid-actions-title)} + (tr "workspace.layout_grid.editor.title") " " [:span {:stl/css :board-name} (:name shape)]] + [:button {:class (stl/css :locate-btn) + :on-click #(st/emit! (dwge/locate-board (:id shape)))} + (tr "workspace.layout_grid.editor.top-bar.locate")] + [:button {:class (stl/css :done-btn) + :on-click #(st/emit! dw/clear-edition-mode)} + (tr "workspace.layout_grid.editor.top-bar.done")]]]) (mf/defc grid-editor-frame {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs index 5dcb1b6d39..3f2c7558b3 100644 --- a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs @@ -10,7 +10,6 @@ [app.main.data.workspace.path :as drp] [app.main.data.workspace.path.shortcuts :as sc] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.shapes.path.common :as pc] [app.util.i18n :as i18n :refer [tr]] @@ -40,7 +39,6 @@ (mf/defc path-actions [{:keys [shape]}] (let [{:keys [edit-mode selected-points snap-toggled] :as all} (mf/deref pc/current-edit-path-ref) content (:content shape) - new-css-system (mf/use-ctx ctx/new-css-system) enabled-buttons (mf/use-memo @@ -111,160 +109,80 @@ (fn [_] (st/emit! (drp/toggle-snap))))] - (if new-css-system - [:div {:class (stl/css :sub-actions)} - [:div {:class (stl/css :sub-actions-group)} + [:div {:class (stl/css :sub-actions)} + [:div {:class (stl/css :sub-actions-group)} - ;; Draw Mode - [:button - {:class (stl/css-case :is-toggled (= edit-mode :draw)) - :title (tr "workspace.path.actions.draw-nodes" (sc/get-tooltip :draw-nodes)) - :on-click on-select-draw-mode} - i/pentool-refactor] + ;; Draw Mode + [:button + {:class (stl/css-case :is-toggled (= edit-mode :draw)) + :title (tr "workspace.path.actions.draw-nodes" (sc/get-tooltip :draw-nodes)) + :on-click on-select-draw-mode} + i/pentool-refactor] - ;; Edit mode - [:button - {:class (stl/css-case :is-toggled (= edit-mode :move)) - :title (tr "workspace.path.actions.move-nodes" (sc/get-tooltip :move-nodes)) - :on-click on-select-edit-mode} - i/move-refactor]] + ;; Edit mode + [:button + {:class (stl/css-case :is-toggled (= edit-mode :move)) + :title (tr "workspace.path.actions.move-nodes" (sc/get-tooltip :move-nodes)) + :on-click on-select-edit-mode} + i/move-refactor]] - [:div {:class (stl/css :sub-actions-group)} - ;; Add Node - [:button - {:disabled (not (:add-node enabled-buttons)) - :title (tr "workspace.path.actions.add-node" (sc/get-tooltip :add-node)) - :on-click on-add-node} - i/add-refactor] + [:div {:class (stl/css :sub-actions-group)} + ;; Add Node + [:button + {:disabled (not (:add-node enabled-buttons)) + :title (tr "workspace.path.actions.add-node" (sc/get-tooltip :add-node)) + :on-click on-add-node} + i/add-refactor] - ;; Remove node - [:button - {:disabled (not (:remove-node enabled-buttons)) - :title (tr "workspace.path.actions.delete-node" (sc/get-tooltip :delete-node)) - :on-click on-remove-node} - i/remove-refactor]] + ;; Remove node + [:button + {:disabled (not (:remove-node enabled-buttons)) + :title (tr "workspace.path.actions.delete-node" (sc/get-tooltip :delete-node)) + :on-click on-remove-node} + i/remove-refactor]] - [:div {:class (stl/css :sub-actions-group)} - ;; Merge Nodes - [:button - {:disabled (not (:merge-nodes enabled-buttons)) - :title (tr "workspace.path.actions.merge-nodes" (sc/get-tooltip :merge-nodes)) - :on-click on-merge-nodes} - i/merge-nodes-refactor] + [:div {:class (stl/css :sub-actions-group)} + ;; Merge Nodes + [:button + {:disabled (not (:merge-nodes enabled-buttons)) + :title (tr "workspace.path.actions.merge-nodes" (sc/get-tooltip :merge-nodes)) + :on-click on-merge-nodes} + i/merge-nodes-refactor] - ;; Join Nodes - [:button - {:disabled (not (:join-nodes enabled-buttons)) - :title (tr "workspace.path.actions.join-nodes" (sc/get-tooltip :join-nodes)) - :on-click on-join-nodes} - i/join-nodes-refactor] + ;; Join Nodes + [:button + {:disabled (not (:join-nodes enabled-buttons)) + :title (tr "workspace.path.actions.join-nodes" (sc/get-tooltip :join-nodes)) + :on-click on-join-nodes} + i/join-nodes-refactor] - ;; Separate Nodes - [:button - {:disabled (not (:separate-nodes enabled-buttons)) - :title (tr "workspace.path.actions.separate-nodes" (sc/get-tooltip :separate-nodes)) - :on-click on-separate-nodes} - i/separate-nodes-refactor]] + ;; Separate Nodes + [:button + {:disabled (not (:separate-nodes enabled-buttons)) + :title (tr "workspace.path.actions.separate-nodes" (sc/get-tooltip :separate-nodes)) + :on-click on-separate-nodes} + i/separate-nodes-refactor]] - ;; Make Corner - [:div {:class (stl/css :sub-actions-group)} - [:button - {:disabled (not (:make-corner enabled-buttons)) - :title (tr "workspace.path.actions.make-corner" (sc/get-tooltip :make-corner)) - :on-click on-make-corner} - i/to-corner-refactor] + ;; Make Corner + [:div {:class (stl/css :sub-actions-group)} + [:button + {:disabled (not (:make-corner enabled-buttons)) + :title (tr "workspace.path.actions.make-corner" (sc/get-tooltip :make-corner)) + :on-click on-make-corner} + i/to-corner-refactor] - ;; Make Curve - [:button - {:disabled (not (:make-curve enabled-buttons)) - :title (tr "workspace.path.actions.make-curve" (sc/get-tooltip :make-curve)) - :on-click on-make-curve} - i/to-curve-refactor]] + ;; Make Curve + [:button + {:disabled (not (:make-curve enabled-buttons)) + :title (tr "workspace.path.actions.make-curve" (sc/get-tooltip :make-curve)) + :on-click on-make-curve} + i/to-curve-refactor]] - ;; Toggle snap - [:div {:class (stl/css :sub-actions-group)} - [:button - {:class (stl/css-case :is-toggled snap-toggled) - :title (tr "workspace.path.actions.snap-nodes" (sc/get-tooltip :snap-nodes)) - :on-click on-toggle-snap} - i/snap-nodes-refactor]]] - - - - [:div.path-actions - [:div.viewport-actions-group - - ;; Draw Mode - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when (= edit-mode :draw) "is-toggled") - :alt (tr "workspace.path.actions.draw-nodes" (sc/get-tooltip :draw-nodes)) - :on-click on-select-draw-mode} - i/pen] - - ;; Edit mode - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when (= edit-mode :move) "is-toggled") - :alt (tr "workspace.path.actions.move-nodes" (sc/get-tooltip :move-nodes)) - :on-click on-select-edit-mode} - i/pointer-inner]] - - [:div.viewport-actions-group - ;; Add Node - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when-not (:add-node enabled-buttons) "is-disabled") - :alt (tr "workspace.path.actions.add-node" (sc/get-tooltip :add-node)) - :on-click on-add-node} - i/nodes-add] - - ;; Remove node - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when-not (:remove-node enabled-buttons) "is-disabled") - :alt (tr "workspace.path.actions.delete-node" (sc/get-tooltip :delete-node)) - :on-click on-remove-node} - i/nodes-remove]] - - [:div.viewport-actions-group - ;; Merge Nodes - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when-not (:merge-nodes enabled-buttons) "is-disabled") - :alt (tr "workspace.path.actions.merge-nodes" (sc/get-tooltip :merge-nodes)) - :on-click on-merge-nodes} - i/nodes-merge] - - ;; Join Nodes - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when-not (:join-nodes enabled-buttons) "is-disabled") - :alt (tr "workspace.path.actions.join-nodes" (sc/get-tooltip :join-nodes)) - :on-click on-join-nodes} - i/nodes-join] - - ;; Separate Nodes - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when-not (:separate-nodes enabled-buttons) "is-disabled") - :alt (tr "workspace.path.actions.separate-nodes" (sc/get-tooltip :separate-nodes)) - :on-click on-separate-nodes} - i/nodes-separate]] - - ;; Make Corner - [:div.viewport-actions-group - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when-not (:make-corner enabled-buttons) "is-disabled") - :alt (tr "workspace.path.actions.make-corner" (sc/get-tooltip :make-corner)) - :on-click on-make-corner} - i/nodes-corner] - - ;; Make Curve - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when-not (:make-curve enabled-buttons) "is-disabled") - :alt (tr "workspace.path.actions.make-curve" (sc/get-tooltip :make-curve)) - :on-click on-make-curve} - i/nodes-curve]] - - ;; Toggle snap - [:div.viewport-actions-group - [:div.viewport-actions-entry.tooltip.tooltip-bottom - {:class (when snap-toggled "is-toggled") - :alt (tr "workspace.path.actions.snap-nodes" (sc/get-tooltip :snap-nodes)) - :on-click on-toggle-snap} - i/nodes-snap]]]))) + ;; Toggle snap + [:div {:class (stl/css :sub-actions-group)} + [:button + {:class (stl/css-case :is-toggled snap-toggled) + :title (tr "workspace.path.actions.snap-nodes" (sc/get-tooltip :snap-nodes)) + :on-click on-toggle-snap} + i/snap-nodes-refactor]]])) diff --git a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs index fb295276f0..babee74956 100644 --- a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs @@ -13,7 +13,6 @@ [app.main.fonts :as fonts] [app.main.rasterizer :as thr] [app.main.store :as st] - [app.main.ui.context :as ctx] [app.main.ui.css-cursors :as cur] [app.util.dom :as dom] [app.util.keyboard :as kbd] @@ -51,8 +50,7 @@ (mf/defc pixel-overlay {::mf/wrap-props false} [props] - (let [new-css-system (mf/use-ctx ctx/new-css-system) - vport (unchecked-get props "vport") + (let [vport (unchecked-get props "vport") viewport-ref (unchecked-get props "viewport-ref") viewport-node (mf/ref-val viewport-ref) @@ -81,8 +79,8 @@ (when-let [zoom-view-node (dom/get-element "picker-detail")] (when-not (mf/ref-val zoom-view-context) (mf/set-ref-val! zoom-view-context (.getContext zoom-view-node "2d"))) - (let [canvas-width (if new-css-system 260 200) - canvas-height (if new-css-system 140 160) + (let [canvas-width 260 + canvas-height 140 {brx :left bry :top} (dom/get-bounding-rect viewport-node) x (mth/floor (- (.-clientX event) brx)) @@ -100,10 +98,10 @@ ;; I don't know why, but the zoom view is offset by 24px ;; instead of 25. - sx (- x (if new-css-system 32 24)) - sy (- y (if new-css-system 17 20)) - sw (if new-css-system 65 50) - sh (if new-css-system 35 40) + sx (- x 32) + sy (- y 17) + sw 65 + sh 35 dx 0 dy 0 dw canvas-width diff --git a/frontend/src/app/main/ui/workspace/viewport/rules.cljs b/frontend/src/app/main/ui/workspace/viewport/rules.cljs index 87ec78766f..af978fef0f 100644 --- a/frontend/src/app/main/ui/workspace/viewport/rules.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/rules.cljs @@ -6,12 +6,10 @@ (ns app.main.ui.workspace.viewport.rules (:require - [app.common.colors :as colors] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.shapes :as gsh] [app.common.math :as mth] - [app.main.ui.context :as ctx] [app.main.ui.formats :as fmt] [app.main.ui.hooks :as hooks] [app.util.object :as obj] @@ -22,8 +20,7 @@ (def rules-width 1) (def rule-area-size 22) (def rule-area-half-size (/ rule-area-size 2)) -(def rules-background "var(--color-gray-50)") -(def new-css-rules-background "var(--panel-background-color)") +(def rules-background "var(--panel-background-color)") (def selection-area-color "var(--color-primary)") (def selection-area-opacity 0.3) (def over-number-size 50) @@ -31,9 +28,8 @@ (def font-size 12) (def font-family "worksans") -(def font-color colors/gray-30) -(def new-css-font-color "var(--layer-row-foreground-color)") -(def new-css-canvas-border-radius 12) +(def font-color "var(--layer-row-foreground-color)") +(def canvas-border-radius 12) ;; ---------------- ;; RULES @@ -156,9 +152,8 @@ (let [rules-width (* rules-width zoom-inverse) step (calculate-step-size zoom) clip-id (str "clip-rule-" (d/name axis)) - new-css-system (mf/use-ctx ctx/new-css-system) - font-color (if new-css-system new-css-font-color font-color) - rules-background (if new-css-system new-css-rules-background rules-background)] + font-color font-color + rules-background rules-background] [:* (let [{:keys [x y width height]} (get-background-area vbox zoom-inverse axis)] @@ -207,8 +202,7 @@ (mf/defc selection-area [{:keys [vbox zoom-inverse selection-rect offset-x offset-y]}] ;; When using the format-number callls we consider if the guide is associated to a frame and we show the position relative to it with the offset - (let [new-css-system (mf/use-ctx ctx/new-css-system) - rules-background (if new-css-system new-css-rules-background rules-background)] + (let [rules-background rules-background] [:g.selection-area [:g [:rect {:x (:x selection-rect) @@ -306,9 +300,8 @@ (hooks/use-equal-memo)) show-rules? (obj/get props "show-rules?") - new-css-system (mf/use-ctx ctx/new-css-system) - rules-background (if new-css-system new-css-rules-background rules-background) - border-radius (/ new-css-canvas-border-radius zoom) + rules-background rules-background + border-radius (/ canvas-border-radius zoom) selection-rect (mf/use-memo @@ -324,21 +317,20 @@ [:& rules-axis {:zoom zoom :zoom-inverse zoom-inverse :vbox vbox :axis :y :offset offset-y}]]) ;; Draw the rules' rounded corners in the viewport corners - (when new-css-system - (let [{:keys [x y width height]} vbox - rule-area-size (if show-rules? (/ rule-area-size zoom) 0)] - [:* - [:path {:d (round-corner-path-tl (+ x rule-area-size) (+ y rule-area-size) border-radius) - :style {:fill rules-background}}] + (let [{:keys [x y width height]} vbox + rule-area-size (if show-rules? (/ rule-area-size zoom) 0)] + [:* + [:path {:d (round-corner-path-tl (+ x rule-area-size) (+ y rule-area-size) border-radius) + :style {:fill rules-background}}] - [:path {:d (round-corner-path-tr (+ x width (- border-radius)) (+ y rule-area-size) border-radius) - :style {:fill rules-background}}] + [:path {:d (round-corner-path-tr (+ x width (- border-radius)) (+ y rule-area-size) border-radius) + :style {:fill rules-background}}] - [:path {:d (round-corner-path-bl (+ x rule-area-size) (+ y height (- border-radius)) border-radius) - :style {:fill rules-background}}] + [:path {:d (round-corner-path-bl (+ x rule-area-size) (+ y height (- border-radius)) border-radius) + :style {:fill rules-background}}] - [:path {:d (round-corner-path-br (+ x (:width vbox) (- border-radius)) (+ y height (- border-radius)) border-radius) - :style {:fill rules-background}}]])) + [:path {:d (round-corner-path-br (+ x (:width vbox) (- border-radius)) (+ y height (- border-radius)) border-radius) + :style {:fill rules-background}}]]) (when (and show-rules? (some? selection-rect)) [:& selection-area {:zoom zoom From 73b8f3fb17fcdd4e94966164b35504211a0f9eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Wed, 3 Jan 2024 10:34:28 +0100 Subject: [PATCH 25/35] :sparkles: Load debug CSS in local dev only --- frontend/gulpfile.js | 27 ++++++++++++--------- frontend/resources/styles/common/base.scss | 3 --- frontend/resources/styles/debug.scss | 15 ++++++++++++ frontend/resources/templates/index.mustache | 4 +++ 4 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 frontend/resources/styles/debug.scss diff --git a/frontend/gulpfile.js b/frontend/gulpfile.js index eee619276b..ce92a04e28 100644 --- a/frontend/gulpfile.js +++ b/frontend/gulpfile.js @@ -1,6 +1,6 @@ import fs from "fs"; import l from "lodash"; -import path from "path" +import path from "path"; import gulp from "gulp"; import gulpConcat from "gulp-concat"; @@ -9,8 +9,8 @@ import gulpMustache from "gulp-mustache"; import gulpPostcss from "gulp-postcss"; import gulpRename from "gulp-rename"; -import * as sass from 'sass'; -import gsass from 'gulp-sass'; +import * as sass from "sass"; +import gsass from "gulp-sass"; const gulpSass = gsass(sass); import svgSprite from "gulp-svg-sprite"; @@ -204,6 +204,7 @@ function templatePipeline(options) { manifest: manifest, translations: JSON.stringify(locales), themes: JSON.stringify(themes), + isDebug: process.env.NODE_ENV !== "production", }); return gulp.src(input).pipe(tmpl).pipe(gulpRename(name)).pipe(gulp.dest(output)).pipe(touch()); @@ -231,16 +232,16 @@ gulp.task("scss:modules", function () { modules({ getJSON: function (cssFileName, json, outputFileName) { // We do nothing because we don't want the generated JSON files - }, + }, // Calculates the whole css-module selector name. // Should be the same as the one in the file `/src/app/main/style.clj` generateScopedName: function (selector, filename, css) { const dir = path.dirname(filename); const name = path.basename(filename, ".css"); const parts = dir.split("/"); - const rootIdx = parts.findIndex(s => s === ROOT_NAME); + const rootIdx = parts.findIndex((s) => s === ROOT_NAME); return parts.slice(rootIdx + 1).join("_") + "_" + name + "__" + selector; - }, + }, }), autoprefixer(), ]), @@ -249,13 +250,15 @@ gulp.task("scss:modules", function () { }); gulp.task("scss:main", function () { + const sources = [`${paths.resources}styles/main-default.scss`, `${paths.resources}styles/debug.scss`]; + return gulp - .src(paths.resources + "styles/main-default.scss") - .pipe(gulpSass.sync({ - includePaths: [ - "./node_modules/animate.css" - ] - })) + .src(sources) + .pipe( + gulpSass.sync({ + includePaths: ["./node_modules/animate.css"], + }), + ) .pipe(gulpPostcss([autoprefixer])) .pipe(gulp.dest(paths.output + "css/")); }); diff --git a/frontend/resources/styles/common/base.scss b/frontend/resources/styles/common/base.scss index 6654083ac6..fd1e4ecb0f 100644 --- a/frontend/resources/styles/common/base.scss +++ b/frontend/resources/styles/common/base.scss @@ -17,9 +17,6 @@ body { width: 100vw; height: 100vh; overflow: hidden; - - background-color: red; //debugger colors - color: yellow; //debugger colors } #app { diff --git a/frontend/resources/styles/debug.scss b/frontend/resources/styles/debug.scss new file mode 100644 index 0000000000..dda48e1fc0 --- /dev/null +++ b/frontend/resources/styles/debug.scss @@ -0,0 +1,15 @@ +// 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 + +// NOTE: This CSS only gets included when the NODE_ENV env var +// is *not* set to `production`. +// It is useful to have some styles that are useful in local dev, like +// debugging. + +body { + background-color: red; + color: yellow; +} diff --git a/frontend/resources/templates/index.mustache b/frontend/resources/templates/index.mustache index 14f26d76a8..77475d7e30 100644 --- a/frontend/resources/templates/index.mustache +++ b/frontend/resources/templates/index.mustache @@ -4,6 +4,7 @@ Penpot - Design Freedom for Teams + @@ -17,6 +18,9 @@ + {{#isDebug}} + + {{/isDebug}} From 9cfc00ce973a7149771bcd71555a64c3a231c422 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 4 Jan 2024 11:48:53 +0100 Subject: [PATCH 26/35] :bug: Fix remap colors on binary import --- backend/src/app/rpc/commands/binfile.clj | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backend/src/app/rpc/commands/binfile.clj b/backend/src/app/rpc/commands/binfile.clj index 7e7327b32e..e3015c023c 100644 --- a/backend/src/app/rpc/commands/binfile.clj +++ b/backend/src/app/rpc/commands/binfile.clj @@ -593,6 +593,7 @@ (declare lookup-index) (declare update-index) (declare relink-media) +(declare relink-colors) (declare relink-shapes) (defmulti read-import ::version) @@ -723,6 +724,7 @@ (update :pages-index relink-shapes) (update :components relink-shapes) (update :media relink-media) + (update :colors relink-colors) (d/without-nils)))))) @@ -997,6 +999,17 @@ media media)) +(defn- relink-colors + "A function responsible of process the :colors attr of file data and + remap the old ids with the new ones." + [colors] + (reduce-kv (fn [res k v] + (if (:image v) + (update-in res [k :image :id] lookup-index) + res)) + colors + colors)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; HIGH LEVEL API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From 93bf8c1478ba5ec397b8aee63ab7b93faa3cb2fc Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 4 Jan 2024 12:01:46 +0100 Subject: [PATCH 27/35] :bug: Fix colors with image fill name --- frontend/src/app/main/ui/components/color_bullet_new.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/components/color_bullet_new.cljs b/frontend/src/app/main/ui/components/color_bullet_new.cljs index 6af3f502b4..f15f3549c8 100644 --- a/frontend/src/app/main/ui/components/color_bullet_new.cljs +++ b/frontend/src/app/main/ui/components/color_bullet_new.cljs @@ -75,5 +75,5 @@ :on-click on-click :on-double-click on-double-click} (if (some? image) - (tr "media.image") + (or name (tr "media.image")) (or name color (uc/gradient-type->string (:type gradient))))]))) From 746d89824522ae74a38fc8d94852b04d0688fe3f Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 2 Jan 2024 21:41:49 +0100 Subject: [PATCH 28/35] :sparkles: Improve the db api efficiency Mainly setup proper defaults and reduce unnecesary allocations on every db api call. --- backend/deps.edn | 2 +- backend/src/app/db.clj | 144 +++++++++++++----- backend/src/app/db/sql.clj | 33 ++-- backend/src/app/features/components_v2.clj | 7 +- backend/src/app/features/fdata.clj | 5 +- backend/src/app/loggers/webhooks.clj | 6 +- backend/src/app/rpc/commands/audit.clj | 2 +- backend/src/app/rpc/commands/auth.clj | 6 +- backend/src/app/rpc/commands/binfile.clj | 2 +- backend/src/app/rpc/commands/comments.clj | 27 ++-- backend/src/app/rpc/commands/files.clj | 29 ++-- .../src/app/rpc/commands/files_thumbnails.clj | 14 +- backend/src/app/rpc/commands/files_update.clj | 3 +- backend/src/app/rpc/commands/fonts.clj | 15 +- backend/src/app/rpc/commands/management.clj | 6 +- backend/src/app/rpc/commands/media.clj | 3 +- backend/src/app/rpc/commands/profile.clj | 12 +- backend/src/app/rpc/commands/projects.clj | 6 +- backend/src/app/rpc/commands/teams.clj | 3 +- backend/src/app/rpc/commands/webhooks.clj | 3 +- backend/src/app/srepl/cli.clj | 13 +- backend/src/app/storage.clj | 6 +- backend/src/app/storage/gc_deleted.clj | 5 +- backend/src/app/tasks/file_gc.clj | 6 +- backend/src/app/tasks/objects_gc.clj | 40 ++--- backend/src/app/tasks/orphan_teams_gc.clj | 3 +- .../rpc_file_thumbnails_test.clj | 9 +- .../test/backend_tests/rpc_profile_test.clj | 4 +- 28 files changed, 228 insertions(+), 186 deletions(-) diff --git a/backend/deps.edn b/backend/deps.edn index b3cacd663a..d3c9893183 100644 --- a/backend/deps.edn +++ b/backend/deps.edn @@ -26,7 +26,7 @@ :git/url "https://github.com/funcool/yetti.git" :exclusions [org.slf4j/slf4j-api]} - com.github.seancorfield/next.jdbc {:mvn/version "1.3.894"} + com.github.seancorfield/next.jdbc {:mvn/version "1.3.909"} metosin/reitit-core {:mvn/version "0.6.0"} nrepl/nrepl {:mvn/version "1.1.0"} cider/cider-nrepl {:mvn/version "0.43.1"} diff --git a/backend/src/app/db.clj b/backend/src/app/db.clj index 3577370222..b1c8476a76 100644 --- a/backend/src/app/db.clj +++ b/backend/src/app/db.clj @@ -19,6 +19,7 @@ [app.util.json :as json] [app.util.time :as dt] [clojure.java.io :as io] + [clojure.set :as set] [clojure.spec.alpha :as s] [integrant.core :as ig] [next.jdbc :as jdbc] @@ -239,6 +240,10 @@ (ex/raise :type :internal :code :unable-resolve-pool)))) +(defn get-update-count + [result] + (:next.jdbc/update-count result)) + (defn get-connection [cfg-or-conn] (if (connection? cfg-or-conn) @@ -265,48 +270,120 @@ :code :unable-resolve-connectable :hint "expected conn, pool or system"))) +(def ^:private params-mapping + {::return-keys? :return-keys + ::return-keys :return-keys}) + +(defn rename-opts + [opts] + (set/rename-keys opts params-mapping)) + +(def ^:private default-insert-opts + {:builder-fn sql/as-kebab-maps + :return-keys true}) + (def ^:private default-opts {:builder-fn sql/as-kebab-maps}) (defn exec! - ([ds sv] - (-> (get-connectable ds) - (jdbc/execute! sv default-opts))) + ([ds sv] (exec! ds sv nil)) ([ds sv opts] - (-> (get-connectable ds) - (jdbc/execute! sv (into default-opts (sql/adapt-opts opts)))))) + (let [conn (get-connectable ds) + opts (if (empty? opts) + default-opts + (into default-opts (rename-opts opts)))] + (jdbc/execute! conn sv opts)))) (defn exec-one! - ([ds sv] - (-> (get-connectable ds) - (jdbc/execute-one! sv default-opts))) + ([ds sv] (exec-one! ds sv nil)) ([ds sv opts] - (-> (get-connectable ds) - (jdbc/execute-one! sv (into default-opts (sql/adapt-opts opts)))))) + (let [conn (get-connectable ds) + opts (if (empty? opts) + default-opts + (into default-opts (rename-opts opts)))] + (jdbc/execute-one! conn sv opts)))) (defn insert! - [ds table params & {:as opts :keys [::return-keys?] :or {return-keys? true}}] - (-> (get-connectable ds) - (exec-one! (sql/insert table params opts) - (assoc opts ::return-keys? return-keys?)))) + "A helper that builds an insert sql statement and executes it. By + default returns the inserted row with all the field; you can delimit + the returned columns with the `::columns` option." + [ds table params & {:as opts}] + (let [conn (get-connectable ds) + sql (sql/insert table params opts) + opts (if (empty? opts) + default-insert-opts + (into default-insert-opts (rename-opts opts)))] + (jdbc/execute-one! conn sql opts))) -(defn insert-multi! - [ds table cols rows & {:as opts :keys [::return-keys?] :or {return-keys? true}}] - (-> (get-connectable ds) - (exec! (sql/insert-multi table cols rows opts) - (assoc opts ::return-keys? return-keys?)))) +(defn insert-many! + "An optimized version of `insert!` that perform insertion of multiple + values at once. + + This expands to a single SQL statement with placeholders for every + value being inserted. For large data sets, this may exceed the limit + of sql string size and/or number of parameters." + [ds table cols rows & {:as opts}] + (let [conn (get-connectable ds) + sql (sql/insert-many table cols rows opts) + opts (if (empty? opts) + default-insert-opts + (into default-insert-opts (rename-opts opts))) + opts (update opts :return-keys boolean)] + (jdbc/execute! conn sql opts))) (defn update! - [ds table params where & {:as opts :keys [::return-keys?] :or {return-keys? true}}] - (-> (get-connectable ds) - (exec-one! (sql/update table params where opts) - (assoc opts ::return-keys? return-keys?)))) + "A helper that build an UPDATE SQL statement and executes it. + + Given a connectable object, a table name, a hash map of columns and + values to set, and either a hash map of columns and values to search + on or a vector of a SQL where clause and parameters, perform an + update on the table. + + By default returns an object with the number of affected rows; a + complete row can be returned if you pass `::return-keys` with `true` + or with a vector of columns. + + Also it can be combined with the `::many` option if you perform an + update to multiple rows and you want all the affected rows to be + returned." + [ds table params where & {:as opts}] + (let [conn (get-connectable ds) + sql (sql/update table params where opts) + opts (if (empty? opts) + default-opts + (into default-opts (rename-opts opts))) + opts (update opts :return-keys boolean)] + (if (::many opts) + (jdbc/execute! conn sql opts) + (jdbc/execute-one! conn sql opts)))) (defn delete! - [ds table params & {:as opts :keys [::return-keys?] :or {return-keys? true}}] - (-> (get-connectable ds) - (exec-one! (sql/delete table params opts) - (assoc opts ::return-keys? return-keys?)))) + "A helper that builds an DELETE SQL statement and executes it. + + Given a connectable object, a table name, and either a hash map of columns + and values to search on or a vector of a SQL where clause and parameters, + perform a delete on the table. + + By default returns an object with the number of affected rows; a + complete row can be returned if you pass `::return-keys` with `true` + or with a vector of columns. + + Also it can be combined with the `::many` option if you perform an + update to multiple rows and you want all the affected rows to be + returned." + [ds table params & {:as opts}] + (let [conn (get-connectable ds) + sql (sql/delete table params opts) + opts (if (empty? opts) + default-opts + (into default-opts (rename-opts opts)))] + (if (::many opts) + (jdbc/execute! conn sql opts) + (jdbc/execute-one! conn sql opts)))) + +(defn query + [ds table params & {:as opts}] + (exec! ds (sql/select table params opts) opts)) (defn is-row-deleted? [{:keys [deleted-at]}] @@ -320,7 +397,7 @@ [ds table params & {:as opts}] (let [rows (exec! ds (sql/select table params opts)) rows (cond->> rows - (::remove-deleted? opts true) + (::remove-deleted opts true) (remove is-row-deleted?))] (first rows))) @@ -329,7 +406,7 @@ filters. Raises :not-found exception if no object is found." [ds table params & {:as opts}] (let [row (get* ds table params opts)] - (when (and (not row) (::check-deleted? opts true)) + (when (and (not row) (::check-deleted opts true)) (ex/raise :type :not-found :code :object-not-found :table table @@ -364,10 +441,6 @@ [ds table id & {:as opts}] (get ds table {:id id} opts)) -(defn query - [ds table params & {:as opts}] - (exec! ds (sql/select table params opts))) - (defn pgobject? ([v] (instance? PGobject v)) @@ -567,11 +640,6 @@ (.setType "jsonb") (.setValue (json/encode-str data))))) -(defn get-update-count - [result] - (:next.jdbc/update-count result)) - - ;; --- Locks (def ^:private siphash-state diff --git a/backend/src/app/db/sql.clj b/backend/src/app/db/sql.clj index 4b002f41b1..37814733de 100644 --- a/backend/src/app/db/sql.clj +++ b/backend/src/app/db/sql.clj @@ -8,7 +8,6 @@ (:refer-clojure :exclude [update]) (:require [app.db :as-alias db] - [clojure.set :as set] [clojure.string :as str] [next.jdbc.optional :as jdbc-opt] [next.jdbc.sql.builder :as sql])) @@ -20,14 +19,6 @@ {:table-fn snake-case :column-fn snake-case}) -(def params-mapping - {::db/return-keys? :return-keys - ::db/columns :columns}) - -(defn adapt-opts - [opts] - (set/rename-keys opts params-mapping)) - (defn as-kebab-maps [rs opts] (jdbc-opt/as-unqualified-modified-maps rs (assoc opts :label-fn kebab-case))) @@ -42,7 +33,7 @@ (assoc :suffix "ON CONFLICT DO NOTHING"))] (sql/for-insert table key-map opts)))) -(defn insert-multi +(defn insert-many [table cols rows opts] (let [opts (merge default-opts opts)] (sql/for-insert-multi table cols rows opts))) @@ -53,11 +44,9 @@ ([table where-params opts] (let [opts (merge default-opts opts) opts (cond-> opts - (::db/columns opts) (assoc :columns (::db/columns opts)) - (::db/for-update? opts) (assoc :suffix "FOR UPDATE") - (::db/for-share? opts) (assoc :suffix "FOR KEY SHARE") - (:for-update opts) (assoc :suffix "FOR UPDATE") - (:for-key-share opts) (assoc :suffix "FOR KEY SHARE"))] + (::columns opts) (assoc :columns (::columns opts)) + (::for-update opts) (assoc :suffix "FOR UPDATE") + (::for-share opts) (assoc :suffix "FOR KEY SHARE"))] (sql/for-query table where-params opts)))) (defn update @@ -65,11 +54,9 @@ (update table key-map where-params nil)) ([table key-map where-params opts] (let [opts (into default-opts opts) - opts (if-let [columns (::db/columns opts)] - (let [columns (if (seq columns) - (sql/as-cols columns opts) - "*")] - (assoc opts :suffix (str "RETURNING " columns))) + keys (::db/return-keys opts) + opts (if (vector? keys) + (assoc opts :suffix (str "RETURNING " (sql/as-cols keys opts))) opts)] (sql/for-update table key-map where-params opts)))) @@ -77,5 +64,9 @@ ([table where-params] (delete table where-params nil)) ([table where-params opts] - (let [opts (merge default-opts opts)] + (let [opts (merge default-opts opts) + keys (::db/return-keys opts) + opts (if (vector? keys) + (assoc opts :suffix (str "RETURNING " (sql/as-cols keys opts))) + opts)] (sql/for-delete table where-params opts)))) diff --git a/backend/src/app/features/components_v2.clj b/backend/src/app/features/components_v2.clj index 99074dd598..1dc9f8325d 100644 --- a/backend/src/app/features/components_v2.clj +++ b/backend/src/app/features/components_v2.clj @@ -816,8 +816,7 @@ {:data (blob/encode (:data file)) :features (db/create-array conn "text" (:features file)) :revn (:revn file)} - {:id (:id file)} - {::db/return-keys? false}) + {:id (:id file)}) (dissoc file :data))) @@ -900,7 +899,9 @@ (conj "styles/v2"))] (db/update! conn :team {:features (db/create-array conn "text" features)} - {:id team-id}))))))) + {:id team-id}) + + nil)))))) (finally (some-> *semaphore* ps/release!) (let [elapsed (tpoint)] diff --git a/backend/src/app/features/fdata.clj b/backend/src/app/features/fdata.clj index 832d3360d0..d04369d5d8 100644 --- a/backend/src/app/features/fdata.clj +++ b/backend/src/app/features/fdata.clj @@ -11,6 +11,7 @@ [app.common.exceptions :as ex] [app.common.logging :as l] [app.db :as db] + [app.db.sql :as-alias sql] [app.util.blob :as blob] [app.util.objects-map :as omap] [app.util.pointer-map :as pmap])) @@ -38,8 +39,8 @@ [system file-id id] (let [{:keys [content]} (db/get system :file-data-fragment {:id id :file-id file-id} - {::db/columns [:content] - ::db/check-deleted? false})] + {::sql/columns [:content] + ::db/check-deleted false})] (when-not content (ex/raise :type :internal :code :fragment-not-found diff --git a/backend/src/app/loggers/webhooks.clj b/backend/src/app/loggers/webhooks.clj index eb0f14fc8c..00ebd3f383 100644 --- a/backend/src/app/loggers/webhooks.clj +++ b/backend/src/app/loggers/webhooks.clj @@ -111,9 +111,11 @@ " where id=?") err (:id whook)] - res (db/exec-one! pool sql {::db/return-keys? true})] + res (db/exec-one! pool sql {::db/return-keys true})] (when (>= (:error-count res) max-errors) - (db/update! pool :webhook {:is-active false} {:id (:id whook)}))) + (db/update! pool :webhook + {:is-active false} + {:id (:id whook)}))) (db/update! pool :webhook {:updated-at (dt/now) diff --git a/backend/src/app/rpc/commands/audit.clj b/backend/src/app/rpc/commands/audit.clj index fa56087219..76bd6e1880 100644 --- a/backend/src/app/rpc/commands/audit.clj +++ b/backend/src/app/rpc/commands/audit.clj @@ -48,7 +48,7 @@ (map event->row)) events (sequence xform events)] (when (seq events) - (db/insert-multi! pool :audit-log event-columns events)))) + (db/insert-many! pool :audit-log event-columns events)))) (def schema:event [:map {:title "Event"} diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index d3be9ac1b8..949d528acf 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -133,7 +133,8 @@ (update-password [conn profile-id] (let [pwd (profile/derive-password cfg password)] - (db/update! conn :profile {:password pwd} {:id profile-id})))] + (db/update! conn :profile {:password pwd} {:id profile-id}) + nil))] (db/with-atomic [conn pool] (->> (validate-token token) @@ -303,7 +304,8 @@ (-> (db/update! conn :profile {:default-team-id (:id team) :default-project-id (:default-project-id team)} - {:id id}) + {:id id} + {::db/return-keys true}) (profile/decode-row)))) diff --git a/backend/src/app/rpc/commands/binfile.clj b/backend/src/app/rpc/commands/binfile.clj index e3015c023c..3ccb22a0f0 100644 --- a/backend/src/app/rpc/commands/binfile.clj +++ b/backend/src/app/rpc/commands/binfile.clj @@ -317,7 +317,7 @@ [cfg file-id] (db/run! cfg (fn [{:keys [::db/conn] :as cfg}] (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)] - (some-> (db/get* conn :file {:id file-id} {::db/remove-deleted? false}) + (some-> (db/get* conn :file {:id file-id} {::db/remove-deleted false}) (files/decode-row) (update :data feat.fdata/process-pointers deref)))))) diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj index 99f6094b4b..9e1a9d4365 100644 --- a/backend/src/app/rpc/commands/comments.clj +++ b/backend/src/app/rpc/commands/comments.clj @@ -12,6 +12,7 @@ [app.common.spec :as us] [app.common.uuid :as uuid] [app.db :as db] + [app.db.sql :as sql] [app.features.fdata :as feat.fdata] [app.loggers.audit :as-alias audit] [app.loggers.webhooks :as-alias webhooks] @@ -62,8 +63,8 @@ (decode-row))) (defn- get-comment - [conn comment-id & {:keys [for-update?]}] - (db/get-by-id conn :comment comment-id {:for-update for-update?})) + [conn comment-id & {:as opts}] + (db/get-by-id conn :comment comment-id opts)) (defn- get-next-seqn [conn file-id] @@ -375,7 +376,7 @@ {::doc/added "1.15"} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id id share-id] :as params}] (db/with-atomic [conn pool] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::db/for-update? true)] + (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (upsert-comment-thread-status! conn profile-id id)))) @@ -392,7 +393,7 @@ {::doc/added "1.15"} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id id is-resolved share-id] :as params}] (db/with-atomic [conn pool] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::db/for-update? true)] + (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (db/update! conn :comment-thread {:is-resolved is-resolved} @@ -415,7 +416,7 @@ [cfg {:keys [::rpc/profile-id ::rpc/request-at thread-id share-id content]}] (db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}] - (let [{:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::db/for-update? true) + (let [{:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true) {:keys [team-id project-id page-name] :as file} (get-file cfg file-id page-id)] (files/check-comment-permissions! conn profile-id (:id file) share-id) @@ -471,8 +472,8 @@ (db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}] - (let [{:keys [thread-id owner-id] :as comment} (get-comment conn id ::db/for-update? true) - {:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::db/for-update? true)] + (let [{:keys [thread-id owner-id] :as comment} (get-comment conn id ::sql/for-update true) + {:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) @@ -504,7 +505,7 @@ {::doc/added "1.15"} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id id share-id]}] (db/with-atomic [conn pool] - (let [{:keys [owner-id file-id] :as thread} (get-comment-thread conn id ::db/for-update? true)] + (let [{:keys [owner-id file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (when-not (= owner-id profile-id) (ex/raise :type :validation @@ -524,14 +525,14 @@ {::doc/added "1.15"} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id id share-id] :as params}] (db/with-atomic [conn pool] - (let [{:keys [owner-id thread-id] :as comment} (get-comment conn id ::db/for-update? true) + (let [{:keys [owner-id thread-id] :as comment} (get-comment conn id ::sql/for-update true) {:keys [file-id] :as thread} (get-comment-thread conn thread-id)] (files/check-comment-permissions! conn profile-id file-id share-id) (when-not (= owner-id profile-id) (ex/raise :type :validation :code :not-allowed)) - (db/delete! conn :comment {:id id})))) - + (db/delete! conn :comment {:id id}) + nil))) ;; --- COMMAND: Update comment thread position @@ -544,7 +545,7 @@ {::doc/added "1.15"} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at id position frame-id share-id]}] (db/with-atomic [conn pool] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::db/for-update? true)] + (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (db/update! conn :comment-thread {:modified-at request-at @@ -564,7 +565,7 @@ {::doc/added "1.15"} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at id frame-id share-id]}] (db/with-atomic [conn pool] - (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::db/for-update? true)] + (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)] (files/check-comment-permissions! conn profile-id file-id share-id) (db/update! conn :comment-thread {:modified-at request-at diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 2bb6cd9b66..58b10742d7 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -20,6 +20,7 @@ [app.common.types.file :as ctf] [app.config :as cf] [app.db :as db] + [app.db.sql :as-alias sql] [app.features.fdata :as feat.fdata] [app.loggers.audit :as-alias audit] [app.loggers.webhooks :as-alias webhooks] @@ -238,8 +239,7 @@ (db/update! conn :file {:data (blob/encode (:data file)) :features (db/create-array conn "text" (:features file))} - {:id id} - {::db/return-keys? false}) + {:id id}) (when (contains? (:features file) "fdata/pointer-map") (feat.fdata/persist-pointers! cfg id))) @@ -262,9 +262,9 @@ (when (some? project-id) {:project-id project-id})) file (-> (db/get conn :file params - {::db/check-deleted? (not include-deleted?) - ::db/remove-deleted? (not include-deleted?) - ::db/for-update? lock-for-update?}) + {::db/check-deleted (not include-deleted?) + ::db/remove-deleted (not include-deleted?) + ::sql/for-update lock-for-update?}) (decode-row))] (if migrate? (migrate-file cfg file) @@ -733,7 +733,8 @@ (db/update! conn :file {:name name :modified-at (dt/now)} - {:id id})) + {:id id} + {::db/return-keys true})) (sv/defmethod ::rename-file {::doc/added "1.17" @@ -860,9 +861,7 @@ (let [file (assoc file :is-shared true)] (db/update! conn :file {:is-shared true} - {:id id} - ::db/return-keys? false) - + {:id id}) file) :else @@ -899,7 +898,7 @@ (db/update! conn :file {:deleted-at (dt/now)} {:id file-id} - {::db/columns [:id :name :is-shared :project-id :created-at :modified-at]})) + {::db/return-keys [:id :name :is-shared :project-id :created-at :modified-at]})) (def ^:private schema:delete-file @@ -998,8 +997,8 @@ [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}] (db/with-atomic [conn pool] (check-edition-permissions! conn profile-id file-id) - (unlink-file-from-library conn params))) - + (unlink-file-from-library conn params) + nil)) ;; --- MUTATION COMMAND: update-sync @@ -1008,7 +1007,8 @@ (db/update! conn :file-library-rel {:synced-at (dt/now)} {:file-id file-id - :library-file-id library-id})) + :library-file-id library-id} + {::db/return-keys true})) (def ^:private schema:update-file-library-sync-status [:map {:title "update-file-library-sync-status"} @@ -1031,7 +1031,8 @@ [conn {:keys [file-id date] :as params}] (db/update! conn :file {:ignore-sync-until date} - {:id file-id})) + {:id file-id} + {::db/return-keys true})) (s/def ::ignore-file-library-sync-status (s/keys :req [::rpc/profile-id] diff --git a/backend/src/app/rpc/commands/files_thumbnails.clj b/backend/src/app/rpc/commands/files_thumbnails.clj index c34fedaff1..712c212047 100644 --- a/backend/src/app/rpc/commands/files_thumbnails.clj +++ b/backend/src/app/rpc/commands/files_thumbnails.clj @@ -17,6 +17,7 @@ [app.common.types.shape-tree :as ctt] [app.config :as cf] [app.db :as db] + [app.db.sql :as-alias sql] [app.features.fdata :as feat.fdata] [app.loggers.audit :as-alias audit] [app.loggers.webhooks :as-alias webhooks] @@ -236,8 +237,8 @@ {:file-id file-id :object-id object-id :tag tag} - {::db/remove-deleted? false - ::db/for-update? true}) + {::db/remove-deleted false + ::sql/for-update true}) path (:path media) mtype (:mtype media) @@ -312,14 +313,13 @@ (when-let [{:keys [media-id tag]} (db/get* conn :file-tagged-object-thumbnail {:file-id file-id :object-id object-id} - {::db/for-update? true})] + {::sql/for-update true})] (sto/touch-object! storage media-id) (db/update! conn :file-tagged-object-thumbnail {:deleted-at (dt/now)} {:file-id file-id :object-id object-id - :tag tag} - {::db/return-keys? false}))) + :tag tag}))) (s/def ::delete-file-object-thumbnail (s/keys :req [::rpc/profile-id] @@ -365,8 +365,8 @@ thumb (db/get* conn :file-thumbnail {:file-id file-id :revn revn} - {::db/remove-deleted? false - ::db/for-update? true})] + {::db/remove-deleted false + ::sql/for-update true})] (if (some? thumb) (do diff --git a/backend/src/app/rpc/commands/files_update.clj b/backend/src/app/rpc/commands/files_update.clj index 7a27a834e8..96b92c0d6e 100644 --- a/backend/src/app/rpc/commands/files_update.clj +++ b/backend/src/app/rpc/commands/files_update.clj @@ -250,7 +250,8 @@ :features (db/create-array conn "text" (:features file)) :data (when (take-snapshot? file) (:data file)) - :changes (blob/encode changes)}) + :changes (blob/encode changes)} + {::db/return-keys false}) (db/update! conn :file {:revn (:revn file) diff --git a/backend/src/app/rpc/commands/fonts.clj b/backend/src/app/rpc/commands/fonts.clj index 830efe3e57..c19b8a2854 100644 --- a/backend/src/app/rpc/commands/fonts.clj +++ b/backend/src/app/rpc/commands/fonts.clj @@ -11,6 +11,7 @@ [app.common.schema :as sm] [app.common.uuid :as uuid] [app.db :as db] + [app.db.sql :as-alias sql] [app.loggers.audit :as-alias audit] [app.loggers.webhooks :as-alias webhooks] [app.media :as media] @@ -179,8 +180,7 @@ (db/update! conn :team-font-variant {:font-family name} {:font-id id - :team-id team-id} - {::db/return-keys? false}) + :team-id team-id}) (rph/with-meta (rph/wrap nil) {::audit/replace-props {:id id @@ -201,7 +201,6 @@ ::webhooks/event? true ::sm/params schema:delete-font} [cfg {:keys [::rpc/profile-id id team-id]}] - (db/tx-run! cfg (fn [{:keys [::db/conn ::sto/storage] :as cfg}] (teams/check-edition-permissions! conn profile-id team-id) @@ -209,7 +208,7 @@ {:team-id team-id :font-id id :deleted-at nil} - {::db/for-update? true}) + {::sql/for-update true}) storage (media/configure-assets-storage storage conn) tnow (dt/now)] @@ -220,8 +219,7 @@ (doseq [font fonts] (db/update! conn :team-font-variant {:deleted-at tnow} - {:id (:id font)} - {::db/return-keys? false}) + {:id (:id font)}) (some->> (:woff1-file-id font) (sto/touch-object! storage)) (some->> (:woff2-file-id font) (sto/touch-object! storage)) (some->> (:ttf-file-id font) (sto/touch-object! storage)) @@ -250,13 +248,12 @@ (teams/check-edition-permissions! conn profile-id team-id) (let [variant (db/get conn :team-font-variant {:id id :team-id team-id} - {::db/for-update? true}) + {::sql/for-update true}) storage (media/configure-assets-storage storage conn)] (db/update! conn :team-font-variant {:deleted-at (dt/now)} - {:id (:id variant)} - {::db/return-keys? false}) + {:id (:id variant)}) (some->> (:woff1-file-id variant) (sto/touch-object! storage)) (some->> (:woff2-file-id variant) (sto/touch-object! storage)) diff --git a/backend/src/app/rpc/commands/management.clj b/backend/src/app/rpc/commands/management.clj index 98f08a8672..aaf51c3a0c 100644 --- a/backend/src/app/rpc/commands/management.clj +++ b/backend/src/app/rpc/commands/management.clj @@ -215,7 +215,7 @@ (-> file (update :features #(db/create-array conn "text" %)) (update :data blob/encode)) - {::db/return-keys? false}) + {::db/return-keys false}) ;; The file profile creation is optional, so when no profile is ;; present (when this function is called from profile less @@ -231,10 +231,10 @@ {::db/return-keys? false})) (doseq [params flibs] - (db/insert! conn :file-library-rel params ::db/return-keys? false)) + (db/insert! conn :file-library-rel params ::db/return-keys false)) (doseq [params fmeds] - (db/insert! conn :file-media-object params ::db/return-keys? false)) + (db/insert! conn :file-media-object params ::db/return-keys false)) file)) diff --git a/backend/src/app/rpc/commands/media.clj b/backend/src/app/rpc/commands/media.clj index a357c109c2..a3dc357db5 100644 --- a/backend/src/app/rpc/commands/media.clj +++ b/backend/src/app/rpc/commands/media.clj @@ -157,8 +157,7 @@ (db/update! conn :file {:modified-at (dt/now) :has-media-trimmed false} - {:id file-id} - {::db/return-keys? false}) + {:id file-id}) (db/exec-one! conn [sql:create-file-media-object (or id (uuid/next)) diff --git a/backend/src/app/rpc/commands/profile.clj b/backend/src/app/rpc/commands/profile.clj index 1deacf14ab..5b814abe62 100644 --- a/backend/src/app/rpc/commands/profile.clj +++ b/backend/src/app/rpc/commands/profile.clj @@ -13,6 +13,7 @@ [app.common.uuid :as uuid] [app.config :as cf] [app.db :as db] + [app.db.sql :as-alias sql] [app.email :as eml] [app.http.session :as session] [app.loggers.audit :as audit] @@ -99,7 +100,7 @@ ;; NOTE: we need to retrieve the profile independently if we use ;; it or not for explicit locking and avoid concurrent updates of ;; the same row/object. - (let [profile (-> (db/get-by-id conn :profile profile-id ::db/for-update? true) + (let [profile (-> (db/get-by-id conn :profile profile-id ::sql/for-update true) (decode-row)) ;; Update the profile map with direct params @@ -164,7 +165,7 @@ (defn- validate-password! [{:keys [::db/conn] :as cfg} {:keys [profile-id old-password] :as params}] - (let [profile (db/get-by-id conn :profile profile-id ::db/for-update? true)] + (let [profile (db/get-by-id conn :profile profile-id ::sql/for-update true)] (when (and (not= (:password profile) "!") (not (:valid (verify-password cfg old-password (:password profile))))) (ex/raise :type :validation @@ -176,7 +177,8 @@ (when-not (db/read-only? conn) (db/update! conn :profile {:password (auth/derive-password password)} - {:id id}))) + {:id id}) + nil)) ;; --- MUTATION: Update Photo @@ -202,7 +204,7 @@ (defn update-profile-photo [{:keys [::db/pool ::sto/storage] :as cfg} {:keys [profile-id file] :as params}] (let [photo (upload-photo cfg params) - profile (db/get-by-id pool :profile profile-id ::db/for-update? true)] + profile (db/get-by-id pool :profile profile-id ::sql/for-update true)] ;; Schedule deletion of old photo (when-let [id (:photo-id profile)] @@ -329,7 +331,7 @@ ::sm/params schema:update-profile-props} [{:keys [::db/pool]} {:keys [::rpc/profile-id props]}] (db/with-atomic [conn pool] - (let [profile (get-profile conn profile-id ::db/for-update? true) + (let [profile (get-profile conn profile-id ::sql/for-update true) props (reduce-kv (fn [props k v] ;; We don't accept namespaced keys (if (simple-ident? k) diff --git a/backend/src/app/rpc/commands/projects.clj b/backend/src/app/rpc/commands/projects.clj index 6b4e72091a..b8a555f449 100644 --- a/backend/src/app/rpc/commands/projects.clj +++ b/backend/src/app/rpc/commands/projects.clj @@ -9,6 +9,7 @@ [app.common.data.macros :as dm] [app.common.spec :as us] [app.db :as db] + [app.db.sql :as-alias sql] [app.loggers.audit :as-alias audit] [app.loggers.webhooks :as webhooks] [app.rpc :as-alias rpc] @@ -233,7 +234,7 @@ [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id id name] :as params}] (db/with-atomic [conn pool] (check-edition-permissions! conn profile-id id) - (let [project (db/get-by-id conn :project id ::db/for-update? true)] + (let [project (db/get-by-id conn :project id ::sql/for-update true)] (db/update! conn :project {:name name} {:id id}) @@ -259,7 +260,8 @@ (check-edition-permissions! conn profile-id id) (let [project (db/update! conn :project {:deleted-at (dt/now)} - {:id id :is-default false})] + {:id id :is-default false} + {::db/return-keys true})] (rph/with-meta (rph/wrap) {::audit/props {:team-id (:team-id project) :name (:name project) diff --git a/backend/src/app/rpc/commands/teams.clj b/backend/src/app/rpc/commands/teams.clj index 791bce1d6e..264fca2a1e 100644 --- a/backend/src/app/rpc/commands/teams.clj +++ b/backend/src/app/rpc/commands/teams.clj @@ -963,5 +963,6 @@ (let [invitation (db/delete! conn :team-invitation {:team-id team-id - :email-to (str/lower email)})] + :email-to (str/lower email)} + {::db/return-keys true})] (rph/wrap nil {::audit/props {:invitation-id (:id invitation)}}))))) diff --git a/backend/src/app/rpc/commands/webhooks.clj b/backend/src/app/rpc/commands/webhooks.clj index 1c6b812c56..13a5d02101 100644 --- a/backend/src/app/rpc/commands/webhooks.clj +++ b/backend/src/app/rpc/commands/webhooks.clj @@ -95,7 +95,8 @@ :mtype mtype :error-code nil :error-count 0} - {:id id}) + {:id id} + {::db/return-keys true}) (decode-row))) (sv/defmethod ::create-webhook diff --git a/backend/src/app/srepl/cli.clj b/backend/src/app/srepl/cli.clj index c3a4bd0c12..9b4943bdcf 100644 --- a/backend/src/app/srepl/cli.clj +++ b/backend/src/app/srepl/cli.clj @@ -65,9 +65,8 @@ (let [res (db/update! conn :profile params {:email email - :deleted-at nil} - {::db/return-keys? false})] - (pos? (:next.jdbc/update-count res)))))))) + :deleted-at nil})] + (pos? (db/get-update-count res)))))))) (defmethod exec-command :delete-profile [{:keys [email soft]}] @@ -82,12 +81,10 @@ (let [res (if soft (db/update! conn :profile {:deleted-at (dt/now)} - {:email email :deleted-at nil} - {::db/return-keys? false}) + {:email email :deleted-at nil}) (db/delete! conn :profile - {:email email} - {::db/return-keys? false}))] - (pos? (:next.jdbc/update-count res)))))) + {:email email}))] + (pos? (db/get-update-count res)))))) (defmethod exec-command :search-profile [{:keys [email]}] diff --git a/backend/src/app/storage.clj b/backend/src/app/storage.clj index 5d24f8e688..c27672e2a1 100644 --- a/backend/src/app/storage.clj +++ b/backend/src/app/storage.clj @@ -170,8 +170,7 @@ (let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id) rs (db/update! pool-or-conn :storage-object {:touched-at (dt/now)} - {:id id} - {::db/return-keys? false})] + {:id id})] (pos? (db/get-update-count rs)))) (defn get-object-data @@ -220,8 +219,7 @@ (let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id) res (db/update! pool-or-conn :storage-object {:deleted-at (dt/now)} - {:id id} - {::db/return-keys? false})] + {:id id})] (pos? (db/get-update-count res)))) (dm/export impl/resolve-backend) diff --git a/backend/src/app/storage/gc_deleted.clj b/backend/src/app/storage/gc_deleted.clj index ec90d483fe..2852c8fe6b 100644 --- a/backend/src/app/storage/gc_deleted.clj +++ b/backend/src/app/storage/gc_deleted.clj @@ -47,8 +47,7 @@ [conn ids] (let [ids (db/create-array conn "uuid" ids)] (-> (db/exec-one! conn [sql:delete-sobjects ids]) - (db/get-update-count)))) - + (db/get-update-count)))) (defn- delete-in-bulk! [cfg backend-id ids] @@ -60,7 +59,6 @@ (fn [{:keys [::db/conn ::sto/storage]}] (when-let [ids (lock-ids conn ids)] (let [total (delete-sobjects! conn ids)] - (-> (impl/resolve-backend storage backend-id) (impl/del-objects-in-bulk ids)) @@ -68,7 +66,6 @@ (l/dbg :hint "permanently delete storage object" :id (str id) :backend (name backend-id))) - total)))) (catch Throwable cause (l/err :hint "unexpected error on bulk deletion" diff --git a/backend/src/app/tasks/file_gc.clj b/backend/src/app/tasks/file_gc.clj index 3e75cb728e..dcb92a4570 100644 --- a/backend/src/app/tasks/file_gc.clj +++ b/backend/src/app/tasks/file_gc.clj @@ -249,8 +249,7 @@ (blob/encode))] (db/update! conn :file {:data data} - {:id file-id} - {::db/return-keys? false})) + {:id file-id})) (count unused)))) @@ -315,7 +314,6 @@ ;; Mark file as trimmed (db/update! conn :file {:has-media-trimmed true} - {:id id} - {::db/return-keys? false}) + {:id id}) (feat.fdata/persist-pointers! cfg id)))) diff --git a/backend/src/app/tasks/objects_gc.clj b/backend/src/app/tasks/objects_gc.clj index 4dec5fa0d5..c5e74ce3ac 100644 --- a/backend/src/app/tasks/objects_gc.clj +++ b/backend/src/app/tasks/objects_gc.clj @@ -89,9 +89,7 @@ ;; CASCADE database triggers. This may leave orphan ;; teams, but there is a special task for deleting ;; orphaned teams. - (db/delete! conn :profile - {:id id} - {::db/return-keys? false}) + (db/delete! conn :profile {:id id}) (inc total)) 0))) @@ -118,20 +116,16 @@ (some->> photo-id (sto/touch-object! storage)) ;; And finally, permanently delete the team. - (db/delete! conn :team - {:id id} - {::db/return-keys? false}) + (db/delete! conn :team {:id id}) ;; Mark for deletion in cascade (db/update! conn :team-font-variant {:deleted-at deleted-at} - {:team-id id} - {::db/return-keys? false}) + {:team-id id}) (db/update! conn :project {:deleted-at deleted-at} - {:team-id id} - {::db/return-keys? false}) + {:team-id id}) (inc total)) 0))) @@ -162,9 +156,7 @@ (some->> (:ttf-file-id font) (sto/touch-object! storage)) ;; And finally, permanently delete the team font variant - (db/delete! conn :team-font-variant - {:id id} - {::db/return-keys? false}) + (db/delete! conn :team-font-variant {:id id}) (inc total)) 0))) @@ -187,16 +179,14 @@ :id (str id) :team-id (str team-id) :deleted-at (dt/format-instant deleted-at)) + ;; And finally, permanently delete the project. - (db/delete! conn :project - {:id id} - {::db/return-keys? false}) + (db/delete! conn :project {:id id}) ;; Mark files to be deleted (db/update! conn :file {:deleted-at deleted-at} - {:project-id id} - {::db/return-keys? false}) + {:project-id id}) (inc total)) 0))) @@ -221,25 +211,21 @@ :deleted-at (dt/format-instant deleted-at)) ;; And finally, permanently delete the file. - (db/delete! conn :file - {:id id} - {::db/return-keys? false}) + (db/delete! conn :file {:id id}) ;; Mark file media objects to be deleted (db/update! conn :file-media-object {:deleted-at deleted-at} - {:file-id id} - {::db/return-keys? false}) + {:file-id id}) ;; Mark thumbnails to be deleted (db/update! conn :file-thumbnail {:deleted-at deleted-at} - {:file-id id} - {::db/return-keys? false}) + {:file-id id}) + (db/update! conn :file-tagged-object-thumbnail {:deleted-at deleted-at} - {:file-id id} - {::db/return-keys? false}) + {:file-id id}) (inc total)) 0))) diff --git a/backend/src/app/tasks/orphan_teams_gc.clj b/backend/src/app/tasks/orphan_teams_gc.clj index f7f1daedf5..c04123a831 100644 --- a/backend/src/app/tasks/orphan_teams_gc.clj +++ b/backend/src/app/tasks/orphan_teams_gc.clj @@ -54,7 +54,6 @@ (l/trc :hint "mark orphan team for deletion" :id (str team-id)) (db/update! conn :team {:deleted-at (dt/now)} - {:id team-id} - {::db/return-keys? false}) + {:id team-id}) (inc total)) 0))) diff --git a/backend/test/backend_tests/rpc_file_thumbnails_test.clj b/backend/test/backend_tests/rpc_file_thumbnails_test.clj index d88b5ed9f6..12e5d71586 100644 --- a/backend/test/backend_tests/rpc_file_thumbnails_test.clj +++ b/backend/test/backend_tests/rpc_file_thumbnails_test.clj @@ -140,7 +140,7 @@ (t/is (= 0 (:freeze res)))) ;; check that storage object is still exists but is marked as deleted - (let [row (th/db-get :storage-object {:id (:media-id row1)} {::db/remove-deleted? false})] + (let [row (th/db-get :storage-object {:id (:media-id row1)} {::db/remove-deleted false})] (t/is (some? (:deleted-at row)))) ;; Run the storage gc deleted task, it should permanently delete @@ -152,7 +152,7 @@ (t/is (some? (sto/get-object storage (:media-id row2)))) ;; check that storage object is still exists but is marked as deleted - (let [row (th/db-get :storage-object {:id (:media-id row1)} {::db/remove-deleted? false})] + (let [row (th/db-get :storage-object {:id (:media-id row1)} {::db/remove-deleted false})] (t/is (nil? row)))))) (t/deftest create-file-thumbnail @@ -240,7 +240,7 @@ (t/is (nil? (sto/get-object storage (:media-id row1)))) (t/is (some? (sto/get-object storage (:media-id row2)))) - (let [row (th/db-get :storage-object {:id (:media-id row1)} {::db/remove-deleted? false})] + (let [row (th/db-get :storage-object {:id (:media-id row1)} {::db/remove-deleted false})] (t/is (some? (:deleted-at row)))) ;; Run the storage gc deleted task, it should permanently delete @@ -320,6 +320,3 @@ (let [result (:result out)] (t/is (contains? result "test-key-2")))))) - - - diff --git a/backend/test/backend_tests/rpc_profile_test.clj b/backend/test/backend_tests/rpc_profile_test.clj index 0bfc01fc76..f21dc17ecd 100644 --- a/backend/test/backend_tests/rpc_profile_test.clj +++ b/backend/test/backend_tests/rpc_profile_test.clj @@ -149,7 +149,7 @@ (let [row (th/db-get :team {:id (:default-team-id prof)} - {::db/remove-deleted? false})] + {::db/remove-deleted false})] (t/is (nil? (:deleted-at row)))) (let [result (th/run-task! :orphan-teams-gc {:min-age 0})] @@ -157,7 +157,7 @@ (let [row (th/db-get :team {:id (:default-team-id prof)} - {::db/remove-deleted? false})] + {::db/remove-deleted false})] (t/is (dt/instant? (:deleted-at row)))) ;; query profile after delete From 471fd781741bd0a3e30165c1f3b2ed983b7d8d83 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 3 Jan 2024 15:20:48 +0100 Subject: [PATCH 29/35] :sparkles: Spawn vthread on s3 internal io completion Instead of using platform threads --- backend/src/app/storage/s3.clj | 49 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/backend/src/app/storage/s3.clj b/backend/src/app/storage/s3.clj index 3800be401d..e019ad2676 100644 --- a/backend/src/app/storage/s3.clj +++ b/backend/src/app/storage/s3.clj @@ -39,6 +39,7 @@ software.amazon.awssdk.core.async.AsyncRequestBody software.amazon.awssdk.core.async.AsyncResponseTransformer software.amazon.awssdk.core.client.config.ClientAsyncConfiguration + software.amazon.awssdk.core.client.config.SdkAdvancedAsyncClientOption software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient software.amazon.awssdk.http.nio.netty.SdkEventLoopGroup software.amazon.awssdk.regions.Region @@ -169,32 +170,34 @@ (defn- build-s3-client [{:keys [::region ::endpoint ::io-threads]}] - (let [aconfig (-> (ClientAsyncConfiguration/builder) - (.build)) + (let [executor (px/resolve-executor :virtual) + aconfig (-> (ClientAsyncConfiguration/builder) + (.advancedOption SdkAdvancedAsyncClientOption/FUTURE_COMPLETION_EXECUTOR executor) + (.build)) - sconfig (-> (S3Configuration/builder) - (cond-> (some? endpoint) (.pathStyleAccessEnabled true)) - (.build)) + sconfig (-> (S3Configuration/builder) + (cond-> (some? endpoint) (.pathStyleAccessEnabled true)) + (.build)) - thr-num (or io-threads (min 16 (px/get-available-processors))) - hclient (-> (NettyNioAsyncHttpClient/builder) - (.eventLoopGroupBuilder (-> (SdkEventLoopGroup/builder) - (.numberOfThreads (int thr-num)))) - (.connectionAcquisitionTimeout default-timeout) - (.connectionTimeout default-timeout) - (.readTimeout default-timeout) - (.writeTimeout default-timeout) - (.build)) + thr-num (or io-threads (min 16 (px/get-available-processors))) + hclient (-> (NettyNioAsyncHttpClient/builder) + (.eventLoopGroupBuilder (-> (SdkEventLoopGroup/builder) + (.numberOfThreads (int thr-num)))) + (.connectionAcquisitionTimeout default-timeout) + (.connectionTimeout default-timeout) + (.readTimeout default-timeout) + (.writeTimeout default-timeout) + (.build)) - client (let [builder (S3AsyncClient/builder) - builder (.serviceConfiguration ^S3AsyncClientBuilder builder ^S3Configuration sconfig) - builder (.asyncConfiguration ^S3AsyncClientBuilder builder ^ClientAsyncConfiguration aconfig) - builder (.httpClient ^S3AsyncClientBuilder builder ^NettyNioAsyncHttpClient hclient) - builder (.region ^S3AsyncClientBuilder builder (lookup-region region)) - builder (cond-> ^S3AsyncClientBuilder builder - (some? endpoint) - (.endpointOverride (URI. endpoint)))] - (.build ^S3AsyncClientBuilder builder))] + client (let [builder (S3AsyncClient/builder) + builder (.serviceConfiguration ^S3AsyncClientBuilder builder ^S3Configuration sconfig) + builder (.asyncConfiguration ^S3AsyncClientBuilder builder ^ClientAsyncConfiguration aconfig) + builder (.httpClient ^S3AsyncClientBuilder builder ^NettyNioAsyncHttpClient hclient) + builder (.region ^S3AsyncClientBuilder builder (lookup-region region)) + builder (cond-> ^S3AsyncClientBuilder builder + (some? endpoint) + (.endpointOverride (URI. endpoint)))] + (.build ^S3AsyncClientBuilder builder))] (reify clojure.lang.IDeref From 41287d8fc579dc0aab0f95f5694ff39116c92bd0 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 3 Jan 2024 15:16:14 +0100 Subject: [PATCH 30/35] :zap: Improve migration script performance and api usability --- backend/dev/user.clj | 10 + backend/src/app/config.clj | 5 +- backend/src/app/features/components_v2.clj | 291 +++++++++------- backend/src/app/main.clj | 9 +- backend/src/app/rpc/commands/binfile.clj | 1 + backend/src/app/srepl/components_v2.clj | 369 +++++++++++---------- backend/src/app/svgo.clj | 65 ++++ backend/src/app/worker.clj | 4 +- common/src/app/common/svg.cljc | 36 +- common/src/app/common/svg/optimizer.js | 148 ++++++--- 10 files changed, 559 insertions(+), 379 deletions(-) create mode 100644 backend/src/app/svgo.clj diff --git a/backend/dev/user.clj b/backend/dev/user.clj index 902ba62129..5d0cb7e371 100644 --- a/backend/dev/user.clj +++ b/backend/dev/user.clj @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.exceptions :as ex] + [app.common.files.helpers :as cfh] [app.common.fressian :as fres] [app.common.geom.matrix :as gmt] [app.common.logging :as l] @@ -136,3 +137,12 @@ (add-tap #(locking debug-tap (prn "tap debug:" %))) 1)) + + +(defn calculate-frames + [{:keys [data]}] + (->> (vals (:pages-index data)) + (mapcat (comp vals :objects)) + (filter cfh/is-direct-child-of-root?) + (filter cfh/frame-shape?) + (count))) diff --git a/backend/src/app/config.clj b/backend/src/app/config.clj index f5a1602aff..ef021d7c1b 100644 --- a/backend/src/app/config.clj +++ b/backend/src/app/config.clj @@ -207,6 +207,7 @@ (s/def ::telemetry-uri ::us/string) (s/def ::telemetry-with-taiga ::us/boolean) (s/def ::tenant ::us/string) +(s/def ::svgo-max-procs ::us/integer) (s/def ::config (s/keys :opt-un [::secret-key @@ -326,7 +327,9 @@ ::telemetry-uri ::telemetry-referer ::telemetry-with-taiga - ::tenant])) + ::tenant + + ::svgo-max-procs])) (def default-flags [:enable-backend-api-doc diff --git a/backend/src/app/features/components_v2.clj b/backend/src/app/features/components_v2.clj index 1dc9f8325d..3c5d3e5b0f 100644 --- a/backend/src/app/features/components_v2.clj +++ b/backend/src/app/features/components_v2.clj @@ -39,27 +39,54 @@ [app.rpc.commands.media :as cmd.media] [app.storage :as sto] [app.storage.tmp :as tmp] + [app.svgo :as svgo] [app.util.blob :as blob] [app.util.pointer-map :as pmap] [app.util.time :as dt] [buddy.core.codecs :as bc] [cuerdas.core :as str] [datoteka.io :as io] - [promesa.exec :as px] - [promesa.exec.semaphore :as ps] - [promesa.util :as pu])) + [promesa.core :as p])) -(def ^:dynamic *system* nil) -(def ^:dynamic *stats* nil) -(def ^:dynamic *file-stats* nil) -(def ^:dynamic *team-stats* nil) -(def ^:dynamic *semaphore* nil) -(def ^:dynamic *skip-on-error* true) +(def ^:dynamic *stats* + "A dynamic var for setting up state for collect stats globally." + nil) + +(def ^:dynamic *skip-on-error* + "A dynamic var for setting up the default error behavior." + true) + +(def ^:dynamic ^:private *system* + "An internal var for making the current `system` available to all + internal functions without the need to explicitly pass it top down." + nil) + +(def ^:dynamic ^:private *max-procs* + "A dynamic variable that can optionally indicates the maxumum number + of concurrent graphics migration processes." + nil) + +(def ^:dynamic ^:private *file-stats* + "An internal dynamic var for collect stats by file." + nil) + +(def ^:dynamic ^:private *team-stats* + "An internal dynamic var for collect stats by team." + nil) (def grid-gap 50) (def frame-gap 200) (def max-group-size 50) +(defn decode-row + [{:keys [features data] :as row}] + (cond-> row + (some? features) + (assoc :features (db/decode-pgarray features #{})) + + (some? data) + (assoc :data (blob/decode data)))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; FILE PREPARATION BEFORE MIGRATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -220,19 +247,17 @@ (fn [file-data] ;; Transform component and copy heads to frames, and set the ;; frame-id of its childrens - (letfn [(fix-container - [container] + (letfn [(fix-container [container] (update container :objects update-vals fix-shape)) - (fix-shape - [shape] + (fix-shape [shape] (if (or (nil? (:parent-id shape)) (ctk/instance-head? shape)) (assoc shape - :type :frame ; Old groups must be converted - :fills (or (:fills shape) []) ; to frames and conform to spec - :hide-in-viewer (or (:hide-in-viewer shape) true) - :rx (or (:rx shape) 0) - :ry (or (:ry shape) 0)) + :type :frame ; Old groups must be converted + :fills (or (:fills shape) []) ; to frames and conform to spec + :hide-in-viewer (or (:hide-in-viewer shape) true) + :rx (or (:rx shape) 0) + :ry (or (:ry shape) 0)) shape))] (-> file-data (update :pages-index update-vals fix-container) @@ -310,10 +335,10 @@ (defn- get-asset-groups [assets generic-name] - (let [; Group by first element of the path. + (let [;; Group by first element of the path. groups (d/group-by #(first (cfh/split-path (:path %))) assets) - ; Split large groups in chunks of max-group-size elements + ;; Split large groups in chunks of max-group-size elements groups (loop [groups (seq groups) result {}] (if (empty? groups) @@ -334,15 +359,14 @@ result splits))))))) - ; Sort assets in each group by path + ;; Sort assets in each group by path groups (update-vals groups (fn [assets] (sort-by (fn [{:keys [path name]}] (str/lower (cfh/merge-path-item path name))) - assets))) + assets)))] - ; Sort groups by name - groups (into (sorted-map) groups)] - groups)) + ;; Sort groups by name + (into (sorted-map) groups))) (defn- create-frame [name position width height] @@ -612,14 +636,11 @@ (defn- create-shapes-for-svg [{:keys [id] :as mobj} file-id objects frame-id position] - (let [svg-text (get-svg-content id) - - optimizer (::csvg/optimizer *system*) - svg-text (csvg/optimize optimizer svg-text) - - svg-data (-> (csvg/parse svg-text) - (assoc :name (:name mobj)) - (collect-and-persist-images file-id))] + (let [svg-text (get-svg-content id) + svg-text (svgo/optimize *system* svg-text) + svg-data (-> (csvg/parse svg-text) + (assoc :name (:name mobj)) + (collect-and-persist-images file-id))] (sbuilder/create-svg-shapes svg-data position objects frame-id frame-id #{} false))) @@ -678,9 +699,7 @@ (defn- create-media-grid [fdata page-id frame-id grid media-group] - (let [factory (px/thread-factory :virtual true) - executor (px/fixed-executor :parallelism 10 :factory factory) - process (fn [mobj position] + (let [process (fn [mobj position] (let [position (gpt/add position (gpt/point grid-gap grid-gap)) tp1 (dt/tpoint)] (try @@ -690,7 +709,6 @@ :file-id (str (:id fdata)) :id (str (:id mobj)) :cause cause) - (if-not *skip-on-error* (throw cause) nil)) @@ -699,21 +717,24 @@ :file-id (str (:id fdata)) :media-id (str (:id mobj)) :elapsed (dt/format-duration (tp1)))))))] - (try - (->> (d/zip media-group grid) - (map (fn [[mobj position]] - (sse/tap {:type :migration-progress - :section :graphics - :name (:name mobj)}) - (px/submit! executor (partial process mobj position)))) - (reduce (fn [fdata promise] - (if-let [changes (deref promise)] - (-> (assoc-in fdata [:options :components-v2] true) - (cp/process-changes changes false)) - fdata)) - fdata)) - (finally - (pu/close! executor))))) + + (->> (d/zip media-group grid) + (partition-all (or *max-procs* 1)) + (mapcat (fn [partition] + (->> partition + (map (fn [[mobj position]] + (sse/tap {:type :migration-progress + :section :graphics + :name (:name mobj)}) + (p/vthread (process mobj position)))) + (doall) + (map deref) + (doall)))) + (filter some?) + (reduce (fn [fdata changes] + (-> (assoc-in fdata [:options :components-v2] true) + (cp/process-changes changes false))) + fdata)))) (defn- migrate-graphics [fdata] @@ -759,6 +780,11 @@ (create-media-grid fdata page-id (:id frame) grid assets) (gpt/add position (gpt/point 0 (+ height (* 2 grid-gap) frame-gap)))))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; PRIVATE HELPERS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defn- migrate-fdata [fdata libs] (let [migrated? (dm/get-in fdata [:options :components-v2])] @@ -771,11 +797,22 @@ (defn- get-file [system id] (binding [pmap/*load-fn* (partial fdata/load-pointer system id)] - (-> (files/get-file system id :migrate? false) + (-> (db/get system :file {:id id} + {::db/remove-deleted false + ::db/check-deleted false}) + (decode-row) (update :data assoc :id id) (update :data fdata/process-pointers deref) (fmg/migrate-file)))) + +(defn- get-team + [system team-id] + (-> (db/get system :team {:id team-id} + {::db/remove-deleted false + ::db/check-deleted false}) + (decode-row))) + (defn- validate-file! [file libs throw-on-validate?] (try @@ -791,7 +828,8 @@ (let [file (get-file system id) libs (->> (files/get-file-libraries conn id) - (into [file] (comp (map :id) (map (partial get-file system)))) + (into [file] (comp (map :id) + (map (partial get-file system)))) (d/index-by :id)) file (-> file @@ -820,13 +858,35 @@ (dissoc file :data))) + +(def ^:private sql:get-and-lock-team-files + "SELECT f.id + FROM file AS f + JOIN project AS p ON (p.id = f.project_id) + WHERE p.team_id = ? + FOR UPDATE") + +(defn- get-and-lock-files + [conn team-id] + (->> (db/cursor conn [sql:get-and-lock-team-files team-id]) + (map :id))) + +(defn- update-team-features! + [conn team-id features] + (let [features (db/create-array conn "text" features)] + (db/update! conn :team + {:features features} + {:id team-id}))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; PUBLIC API +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defn migrate-file! - [system file-id & {:keys [validate? throw-on-validate?]}] - (let [tpoint (dt/tpoint) - file-id (if (string? file-id) - (parse-uuid file-id) - file-id)] - (binding [*file-stats* (atom {})] + [system file-id & {:keys [validate? throw-on-validate? max-procs]}] + (let [tpoint (dt/tpoint)] + (binding [*file-stats* (atom {}) + *max-procs* max-procs] (try (l/dbg :hint "migrate:file:start" :file-id (str file-id)) @@ -838,7 +898,6 @@ (process-file system file-id :validate? validate? :throw-on-validate? throw-on-validate?))))) - (finally (let [elapsed (tpoint) components (get @*file-stats* :processed/components 0) @@ -854,75 +913,51 @@ (some-> *team-stats* (swap! update :processed/files (fnil inc 0))))))))) (defn migrate-team! - [system team-id & {:keys [validate? throw-on-validate?]}] - (let [tpoint (dt/tpoint) - team-id (if (string? team-id) - (parse-uuid team-id) - team-id)] - (l/dbg :hint "migrate:team:start" :team-id (dm/str team-id)) + [system team-id & {:keys [validate? throw-on-validate? max-procs]}] + + (l/dbg :hint "migrate:team:start" + :team-id (dm/str team-id)) + + (let [tpoint (dt/tpoint) + + migrate-file + (fn [system file-id] + (migrate-file! system file-id + :max-procs max-procs + :validate? validate? + :throw-on-validate? throw-on-validate?)) + migrate-team + (fn [{:keys [::db/conn] :as system} {:keys [id features] :as team}] + (let [features (-> features + (disj "ephimeral/v2-migration") + (conj "components/v2") + (conj "layout/grid") + (conj "styles/v2"))] + + (run! (partial migrate-file system) + (get-and-lock-files conn id)) + + (update-team-features! conn id features)))] + (binding [*team-stats* (atom {})] (try - ;; We execute this out of transaction because we want this - ;; change to be visible to all other sessions before starting - ;; the migration - (let [sql (str "UPDATE team SET features = " - " array_append(features, 'ephimeral/v2-migration') " - " WHERE id = ?")] - (db/exec-one! system [sql team-id])) - - (db/tx-run! system - (fn [{:keys [::db/conn] :as system}] - ;; Lock the team - (db/exec-one! conn ["SET idle_in_transaction_session_timeout = 0"]) - - (let [{:keys [features] :as team} (-> (db/get conn :team {:id team-id}) - (update :features db/decode-pgarray #{}))] - - (if (contains? features "components/v2") - (l/dbg :hint "team already migrated") - (let [sql (str/concat - "SELECT f.id FROM file AS f " - " JOIN project AS p ON (p.id = f.project_id) " - "WHERE p.team_id = ? AND f.deleted_at IS NULL AND p.deleted_at IS NULL " - "FOR UPDATE")] - - (doseq [file-id (->> (db/exec! conn [sql team-id]) - (map :id))] - (migrate-file! system file-id - :validate? validate? - :throw-on-validate? throw-on-validate?)) - - (let [features (-> features - (disj "ephimeral/v2-migration") - (conj "components/v2") - (conj "layout/grid") - (conj "styles/v2"))] - (db/update! conn :team - {:features (db/create-array conn "text" features)} - {:id team-id}) - - nil)))))) + (db/tx-run! system (fn [system] + (db/exec-one! system ["SET idle_in_transaction_session_timeout = 0"]) + (let [team (get-team system team-id)] + (if (contains? (:features team) "components/v2") + (l/inf :hint "team already migrated") + (migrate-team system team))))) (finally - (some-> *semaphore* ps/release!) - (let [elapsed (tpoint)] + (let [elapsed (tpoint) + components (get @*team-stats* :processed/components 0) + graphics (get @*team-stats* :processed/graphics 0) + files (get @*team-stats* :processed/files 0)] + (some-> *stats* (swap! update :processed/teams (fnil inc 0))) - ;; We execute this out of transaction because we want this - ;; change to be visible to all other sessions before starting - ;; the migration - (let [sql (str "UPDATE team SET features = " - " array_remove(features, 'ephimeral/v2-migration') " - " WHERE id = ?")] - (db/exec-one! system [sql team-id])) - - (let [components (get @*team-stats* :processed/components 0) - graphics (get @*team-stats* :processed/graphics 0) - files (get @*team-stats* :processed/files 0)] - (l/dbg :hint "migrate:team:end" - :team-id (dm/str team-id) - :files files - :components components - :graphics graphics - :elapsed (dt/format-duration elapsed))))))))) - - + (l/dbg :hint "migrate:team:end" + :team-id (dm/str team-id) + :files files + :components components + :graphics graphics + :elapsed (dt/format-duration elapsed)))))))) diff --git a/backend/src/app/main.clj b/backend/src/app/main.clj index dde88473b7..c80210a06b 100644 --- a/backend/src/app/main.clj +++ b/backend/src/app/main.clj @@ -10,7 +10,6 @@ [app.auth.oidc :as-alias oidc] [app.auth.oidc.providers :as-alias oidc.providers] [app.common.logging :as l] - [app.common.svg :as csvg] [app.config :as cf] [app.db :as-alias db] [app.email :as-alias email] @@ -37,6 +36,7 @@ [app.storage.gc-deleted :as-alias sto.gc-deleted] [app.storage.gc-touched :as-alias sto.gc-touched] [app.storage.s3 :as-alias sto.s3] + [app.svgo :as-alias svgo] [app.util.time :as dt] [app.worker :as-alias wrk] [cider.nrepl :refer [cider-nrepl-handler]] @@ -316,7 +316,7 @@ ::mtx/metrics (ig/ref ::mtx/metrics) ::mbus/msgbus (ig/ref ::mbus/msgbus) ::rds/redis (ig/ref ::rds/redis) - ::csvg/optimizer (ig/ref ::csvg/optimizer) + ::svgo/optimizer (ig/ref ::svgo/optimizer) ::rpc/climit (ig/ref ::rpc/climit) ::rpc/rlimit (ig/ref ::rpc/rlimit) @@ -409,8 +409,9 @@ ;; module requires the migrations to run before initialize. ::migrations (ig/ref :app.migrations/migrations)} - ::csvg/optimizer - {} + ::svgo/optimizer + {::wrk/executor (ig/ref ::wrk/executor) + ::svgo/max-procs (cf/get :svgo-max-procs)} ::audit.tasks/archive {::props (ig/ref ::setup/props) diff --git a/backend/src/app/rpc/commands/binfile.clj b/backend/src/app/rpc/commands/binfile.clj index 3ccb22a0f0..c173ec3bb6 100644 --- a/backend/src/app/rpc/commands/binfile.clj +++ b/backend/src/app/rpc/commands/binfile.clj @@ -664,6 +664,7 @@ (case feature "components/v2" (feat.compv2/migrate-file! options file-id + :max-procs 2 :validate? validate? :throw-on-validate? true) diff --git a/backend/src/app/srepl/components_v2.clj b/backend/src/app/srepl/components_v2.clj index 598c13e6d5..049fc3574f 100644 --- a/backend/src/app/srepl/components_v2.clj +++ b/backend/src/app/srepl/components_v2.clj @@ -6,8 +6,6 @@ (ns app.srepl.components-v2 (:require - [app.common.data :as d] - [app.common.data.macros :as dm] [app.common.logging :as l] [app.common.pprint :as pp] [app.db :as db] @@ -19,6 +17,13 @@ [promesa.exec.semaphore :as ps] [promesa.util :as pu])) +(def ^:dynamic *scope* nil) +(def ^:dynamic *semaphore* nil) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; PRIVATE HELPERS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defn- print-stats! [stats] (->> stats @@ -87,210 +92,228 @@ res (db/exec-one! pool [sql])] (:count res))) -(defn migrate-file! - [system file-id & {:keys [rollback?] :or {rollback? true}}] - (l/dbg :hint "migrate:start") - (let [tpoint (dt/tpoint)] - (try - (binding [feat/*stats* (atom {})] +(defn- mark-team-migration! + [{:keys [::db/pool]} team-id] + ;; We execute this out of transaction because we want this + ;; change to be visible to all other sessions before starting + ;; the migration + (let [sql (str "UPDATE team SET features = " + " array_append(features, 'ephimeral/v2-migration') " + " WHERE id = ?")] + (db/exec-one! pool [sql team-id]))) + +(defn- unmark-team-migration! + [{:keys [::db/pool]} team-id] + ;; We execute this out of transaction because we want this + ;; change to be visible to all other sessions before starting + ;; the migration + (let [sql (str "UPDATE team SET features = " + " array_remove(features, 'ephimeral/v2-migration') " + " WHERE id = ?")] + (db/exec-one! pool [sql team-id]))) + +(def ^:private sql:get-teams + "SELECT id, features + FROM team + WHERE deleted_at IS NULL + ORDER BY created_at ASC") + +(defn- get-teams + [conn] + (->> (db/cursor conn sql:get-teams) + (map feat/decode-row))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; PUBLIC API +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn migrate-file! + [system file-id & {:keys [rollback? max-procs] + :or {rollback? true}}] + + (l/dbg :hint "migrate:start" :rollback rollback?) + (let [tpoint (dt/tpoint) + file-id (if (string? file-id) + (parse-uuid file-id) + file-id)] + (binding [feat/*stats* (atom {})] + (try (-> (assoc system ::db/rollback rollback?) - (feat/migrate-file! file-id)) + (feat/migrate-file! file-id :max-procs max-procs)) (-> (deref feat/*stats*) - (assoc :elapsed (dt/format-duration (tpoint))))) + (assoc :elapsed (dt/format-duration (tpoint)))) - (catch Throwable cause - (l/wrn :hint "migrate:error" :cause cause)) + (catch Throwable cause + (l/wrn :hint "migrate:error" :cause cause)) - (finally - (let [elapsed (dt/format-duration (tpoint))] - (l/dbg :hint "migrate:end" :elapsed elapsed)))))) - -(defn migrate-files! - [{:keys [::db/pool] :as system} - & {:keys [chunk-size max-jobs max-items start-at preset rollback? skip-on-error validate?] - :or {chunk-size 10 - skip-on-error true - max-jobs 10 - max-items Long/MAX_VALUE - preset :shutdown-on-failure - rollback? true - validate? false}}] - (letfn [(get-chunk [cursor] - (let [sql (str/concat - "SELECT id, created_at FROM file " - " WHERE created_at < ? AND deleted_at IS NULL " - " ORDER BY created_at desc LIMIT ?") - rows (db/exec! pool [sql cursor chunk-size])] - [(some->> rows peek :created-at) (seq rows)])) - - (get-candidates [] - (->> (d/iteration get-chunk - :vf second - :kf first - :initk (or start-at (dt/now))) - (take max-items) - (map :id)))] - - (l/dbg :hint "migrate:start") - (let [fsem (ps/create :permits max-jobs) - total (get-total-files pool) - stats (atom {:files/total total}) - tpoint (dt/tpoint)] - - (add-watch stats :progress-report (report-progress-files tpoint)) - - (binding [feat/*stats* stats - feat/*semaphore* fsem - feat/*skip-on-error* skip-on-error] - (try - (pu/with-open [scope (px/structured-task-scope :preset preset :factory :virtual)] - - (run! (fn [file-id] - (ps/acquire! feat/*semaphore*) - (px/submit! scope (fn [] - (-> (assoc system ::db/rollback rollback?) - (feat/migrate-file! file-id - :validate? validate? - :throw-on-validate? (not skip-on-error)))))) - (get-candidates)) - - (p/await! scope)) - - (-> (deref feat/*stats*) - (assoc :elapsed (dt/format-duration (tpoint)))) - - (catch Throwable cause - (l/dbg :hint "migrate:error" :cause cause)) - - (finally - (let [elapsed (dt/format-duration (tpoint))] - (l/dbg :hint "migrate:end" :elapsed elapsed)))))))) + (finally + (let [elapsed (dt/format-duration (tpoint))] + (l/dbg :hint "migrate:end" :rollback rollback? :elapsed elapsed))))))) (defn migrate-team! - [{:keys [::db/pool] :as system} team-id - & {:keys [rollback? skip-on-error validate?] - :or {rollback? true skip-on-error true validate? false}}] - (l/dbg :hint "migrate:start") + [{:keys [::db/pool] :as system} team-id & {:keys [rollback? skip-on-error validate? max-procs] + :or {rollback? true + skip-on-error true + validate? false + max-procs 1 } + :as opts}] - (let [total (get-total-files pool :team-id team-id) - stats (atom {:total/files total}) - tpoint (dt/tpoint)] + (l/dbg :hint "migrate:start" :rollback rollback?) + + (let [team-id (if (string? team-id) + (parse-uuid team-id) + team-id) + total (get-total-files pool :team-id team-id) + stats (atom {:total/files total}) + tpoint (dt/tpoint)] (add-watch stats :progress-report (report-progress-files tpoint)) - (try - (binding [feat/*stats* stats - feat/*skip-on-error* skip-on-error] + (binding [feat/*stats* stats + feat/*skip-on-error* skip-on-error] + + (try + (mark-team-migration! system team-id) + (-> (assoc system ::db/rollback rollback?) (feat/migrate-team! team-id + :max-procs max-procs :validate? validate? :throw-on-validate? (not skip-on-error))) (print-stats! (-> (deref feat/*stats*) (dissoc :total/files) - (assoc :elapsed (dt/format-duration (tpoint)))))) + (assoc :elapsed (dt/format-duration (tpoint))))) - (catch Throwable cause - (l/dbg :hint "migrate:error" :cause cause)) + (catch Throwable cause + (l/dbg :hint "migrate:error" :cause cause)) - (finally - (let [elapsed (dt/format-duration (tpoint))] - (l/dbg :hint "migrate:end" :elapsed elapsed)))))) + (finally + (unmark-team-migration! system team-id) -(defn default-on-end - [stats] - (print-stats! - (-> stats - (update :elapsed/total dt/format-duration) - (dissoc :total/teams)))) + (let [elapsed (dt/format-duration (tpoint))] + (l/dbg :hint "migrate:end" :rollback rollback? :elapsed elapsed))))))) (defn migrate-teams! - [{:keys [::db/pool] :as system} - & {:keys [chunk-size max-jobs max-items start-at - rollback? validate? preset skip-on-error - max-time on-start on-progress on-error on-end] - :or {chunk-size 10000 - validate? false - rollback? true - skip-on-error true - on-end default-on-end - preset :shutdown-on-failure - max-jobs Integer/MAX_VALUE - max-items Long/MAX_VALUE}}] + "A REPL helper for migrate all teams. - (letfn [(get-chunk [cursor] - (let [sql (str/concat - "SELECT id, created_at, features FROM team " - " WHERE created_at < ? AND deleted_at IS NULL " - " ORDER BY created_at desc LIMIT ?") - rows (db/exec! pool [sql cursor chunk-size])] - [(some->> rows peek :created-at) (seq rows)])) + This function starts multiple concurrent team migration processes + until thw maximum number of jobs is reached which by default has the + value of `1`. This is controled with the `:max-jobs` option. - (get-candidates [] - (->> (d/iteration get-chunk - :vf second - :kf first - :initk (or start-at (dt/now))) - (map #(update % :features db/decode-pgarray #{})) - (remove #(contains? (:features %) "ephimeral/v2-migration")) - (take max-items) - (map :id))) + Each tram migration process also can start multiple procs for + graphics migration, the total of that procs is controled with the + `:max-procs` option. - (migrate-team [team-id] - (try - (-> (assoc system ::db/rollback rollback?) - (feat/migrate-team! team-id - :validate? validate? - :throw-on-validate? (not skip-on-error))) - (catch Throwable cause - (l/err :hint "unexpected error on processing team" :team-id (dm/str team-id) :cause cause)))) + Internally, the graphics migration process uses SVGO module which by + default has a limited number of maximum concurent + operations (globally), ensure setting up correct number with + PENPOT_SVGO_MAX_PROCS environment variable." - (process-team [scope tpoint mtime team-id] - (ps/acquire! feat/*semaphore*) - (let [ts (tpoint)] - (if (and mtime (neg? (compare mtime ts))) - (l/inf :hint "max time constraint reached" :elapsed (dt/format-duration ts)) - (px/submit! scope (partial migrate-team team-id)))))] + [{:keys [::db/pool] :as system} & {:keys [max-jobs max-procs max-items + rollback? validate? preset + skip-on-error max-time + on-start on-progress on-error on-end] + :or {validate? false + rollback? true + skip-on-error true + preset :shutdown-on-failure + max-jobs 1 + max-procs 10 + max-items Long/MAX_VALUE} + :as opts}] - (l/dbg :hint "migrate:start") + (let [total (get-total-teams pool) + stats (atom {:total/teams (min total max-items)}) - (let [sem (ps/create :permits max-jobs) - total (get-total-teams pool) - stats (atom {:total/teams (min total max-items)}) - tpoint (dt/tpoint) - mtime (some-> max-time dt/duration)] + tpoint (dt/tpoint) + mtime (some-> max-time dt/duration) - (when (fn? on-start) - (on-start {:total total :rollback rollback?})) + scope (px/structured-task-scope :preset preset :factory :virtual) + sjobs (ps/create :permits max-jobs) - (add-watch stats :progress-report (report-progress-teams tpoint on-progress)) + migrate-team + (fn [{:keys [id features] :as team}] + (ps/acquire! sjobs) + (let [ts (tpoint)] + (cond + (and mtime (neg? (compare mtime ts))) + (do + (l/inf :hint "max time constraint reached" + :team-id (str id) + :elapsed (dt/format-duration ts)) + (ps/release! sjobs) + (reduced nil)) - (binding [feat/*stats* stats - feat/*semaphore* sem - feat/*skip-on-error* skip-on-error] + (or (contains? features "ephimeral/v2-migration") + (contains? features "components/v2")) + (do + (l/dbg :hint "skip team" :team-id (str id)) + (ps/release! sjobs)) + + :else + (px/submit! scope (fn [] + (try + (mark-team-migration! system id) + (-> (assoc system ::db/rollback rollback?) + (feat/migrate-team! id + :max-procs max-procs + :validate? validate? + :throw-on-validate? (not skip-on-error))) + (catch Throwable cause + (l/err :hint "unexpected error on processing team" + :team-id (str id) + :cause cause)) + (finally + (ps/release! sjobs) + (unmark-team-migration! system id))))))))] + + (l/dbg :hint "migrate:start" + :rollback rollback? + :total total + :max-jobs max-jobs + :max-procs max-procs + :max-items max-items) + + (add-watch stats :progress-report (report-progress-teams tpoint on-progress)) + + (binding [feat/*stats* stats + feat/*skip-on-error* skip-on-error] + (try + (when (fn? on-start) + (on-start {:total total :rollback rollback?})) + + (db/tx-run! system + (fn [{:keys [::db/conn]}] + (run! (partial migrate-team) + (->> (get-teams conn) + (take max-items))))) (try - (pu/with-open [scope (px/structured-task-scope :preset preset - :factory :virtual)] - (loop [candidates (get-candidates)] - (when-let [team-id (first candidates)] - (when (process-team scope tpoint mtime team-id) - (recur (rest candidates))))) - - (p/await! scope)) - - (when (fn? on-end) - (-> (deref stats) - (assoc :elapsed/total (tpoint)) - (on-end))) - - (catch Throwable cause - (l/dbg :hint "migrate:error" :cause cause) - (when (fn? on-error) - (on-error cause))) - + (p/await! scope) (finally - (let [elapsed (dt/format-duration (tpoint))] - (l/dbg :hint "migrate:end" :elapsed elapsed)))))))) + (pu/close! scope))) + + + (if (fn? on-end) + (-> (deref stats) + (assoc :elapsed/total (tpoint)) + (on-end)) + (-> (deref stats) + (assoc :elapsed/total (tpoint)) + (update :elapsed/total dt/format-duration) + (dissoc :total/teams) + (print-stats!))) + + (catch Throwable cause + (l/dbg :hint "migrate:error" :cause cause) + (when (fn? on-error) + (on-error cause))) + + (finally + (let [elapsed (dt/format-duration (tpoint))] + (l/dbg :hint "migrate:end" + :rollback rollback? + :elapsed elapsed))))))) diff --git a/backend/src/app/svgo.clj b/backend/src/app/svgo.clj new file mode 100644 index 0000000000..70d7c6b2b3 --- /dev/null +++ b/backend/src/app/svgo.clj @@ -0,0 +1,65 @@ +;; 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.svgo + "A SVG Optimizer service" + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.jsrt :as jsrt] + [app.common.logging :as l] + [app.common.spec :as us] + [app.worker :as-alias wrk] + [clojure.spec.alpha :as s] + [integrant.core :as ig] + [promesa.exec :as px] + [promesa.exec.bulkhead :as bh] + [promesa.exec.semaphore :as ps] + [promesa.util :as pu])) + +(def ^:dynamic *semaphore* + "A dynamic variable that can optionally contain a traffic light to + appropriately delimit the use of resources, managed externally." + nil) + +(defn optimize + [system data] + (dm/assert! "expect data to be a string" (string? data)) + + (letfn [(optimize-fn [pool] + (jsrt/run! pool + (fn [context] + (jsrt/set! context "svgData" data) + (jsrt/eval! context "penpotSvgo.optimize(svgData, {plugins: ['safeAndFastPreset']})"))))] + (try + (some-> *semaphore* ps/acquire!) + (let [{:keys [::jsrt/pool ::wrk/executor]} (::optimizer system)] + (dm/assert! "expect optimizer instance" (jsrt/pool? pool)) + (px/invoke! executor (partial optimize-fn pool))) + (finally + (some-> *semaphore* ps/release!))))) + +(s/def ::max-procs (s/nilable ::us/integer)) + +(defmethod ig/pre-init-spec ::optimizer [_] + (s/keys :req [::wrk/executor ::max-procs])) + +(defmethod ig/prep-key ::optimizer + [_ cfg] + (merge {::max-procs 20} (d/without-nils cfg))) + +(defmethod ig/init-key ::optimizer + [_ {:keys [::wrk/executor ::max-procs]}] + (l/inf :hint "initializing svg optimizer pool" :max-procs max-procs) + (let [init (jsrt/resource->source "app/common/svg/optimizer.js") + executor (bh/create :type :executor :executor executor :permits max-procs)] + {::jsrt/pool (jsrt/pool :init init) + ::wrk/executor executor})) + +(defmethod ig/halt-key! ::optimizer + [_ {:keys [::jsrt/pool]}] + (l/info :hint "stopping svg optimizer pool") + (pu/close! pool)) diff --git a/backend/src/app/worker.clj b/backend/src/app/worker.clj index 0ab867971b..0e830ac9a3 100644 --- a/backend/src/app/worker.clj +++ b/backend/src/app/worker.clj @@ -42,8 +42,8 @@ (defmethod ig/init-key ::executor [_ _] - (let [factory (px/thread-factory :prefix "penpot/default/") - executor (px/cached-executor :factory factory :keepalive 30000)] + (let [factory (px/thread-factory :prefix "penpot/default/") + executor (px/cached-executor :factory factory :keepalive 60000)] (l/inf :hint "starting executor") (reify java.lang.AutoCloseable diff --git a/common/src/app/common/svg.cljc b/common/src/app/common/svg.cljc index 39379028f3..bc4f79f19e 100644 --- a/common/src/app/common/svg.cljc +++ b/common/src/app/common/svg.cljc @@ -9,9 +9,6 @@ #?(:cljs ["./svg/optimizer.js" :as svgo]) #?(:clj [clojure.xml :as xml] :cljs [tubax.core :as tubax]) - #?(:clj [integrant.core :as ig]) - #?(:clj [app.common.jsrt :as jsrt]) - #?(:clj [app.common.logging :as l]) [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.matrix :as gmt] @@ -1053,21 +1050,6 @@ :height (d/parse-integer (:height attrs) 0)})))] (reduce-nodes redfn [] svg-data ))) -#?(:cljs - (defn optimize - ([input] (optimize input nil)) - ([input options] - (svgo/optimize input (clj->js options)))) - :clj - (defn optimize - [pool data] - (dm/assert! "expected a valid pool" (jsrt/pool? pool)) - (dm/assert! "expect data to be a string" (string? data)) - (jsrt/run! pool - (fn [context] - (jsrt/set! context "svgData" data) - (jsrt/eval! context "penpotSvgo.optimize(svgData, {})"))))) - #?(:clj (defn- secure-parser-factory [^InputStream input ^XMLHandler handler] @@ -1091,15 +1073,9 @@ (dm/with-open [istream (IOUtils/toInputStream text "UTF-8")] (xml/parse istream secure-parser-factory))))) -#?(:clj - (defmethod ig/init-key ::optimizer - [_ _] - (l/info :hint "initializing svg optimizer pool") - (let [init (jsrt/resource->source "app/common/svg/optimizer.js")] - (jsrt/pool :init init)))) - -#?(:clj - (defmethod ig/halt-key! ::optimizer - [_ pool] - (l/info :hint "stopping svg optimizer pool") - (.close ^java.lang.AutoCloseable pool))) +;; FIXME pass correct plugin set +#?(:cljs + (defn optimize + ([input] (optimize input nil)) + ([input options] + (svgo/optimize input (clj->js options))))) diff --git a/common/src/app/common/svg/optimizer.js b/common/src/app/common/svg/optimizer.js index 70826b8bdb..ccd19b6970 100644 --- a/common/src/app/common/svg/optimizer.js +++ b/common/src/app/common/svg/optimizer.js @@ -29431,12 +29431,13 @@ const optimize = (input, config) => { exports.optimize = optimize; -},{"./svgo/parser.js":322,"./svgo/plugins.js":324,"./svgo/stringifier.js":381,"./svgo/tools.js":383,"lodash/isPlainObject":308}],320:[function(require,module,exports){ +},{"./svgo/parser.js":322,"./svgo/plugins.js":324,"./svgo/stringifier.js":382,"./svgo/tools.js":384,"lodash/isPlainObject":308}],320:[function(require,module,exports){ 'use strict'; exports.builtin = [ require('./plugins/default.js'), require('./plugins/safe.js'), + require('./plugins/safeAndFast.js'), require('./plugins/addAttributesToSVGElement.js'), require('./plugins/addClassesToSVGElement.js'), require('./plugins/cleanupAttrs.js'), @@ -29489,7 +29490,7 @@ exports.builtin = [ require('./plugins/sortDefsChildren.js'), ]; -},{"./plugins/addAttributesToSVGElement.js":328,"./plugins/addClassesToSVGElement.js":329,"./plugins/cleanupAttrs.js":331,"./plugins/cleanupEnableBackground.js":332,"./plugins/cleanupIds.js":333,"./plugins/cleanupListOfValues.js":334,"./plugins/cleanupNumericValues.js":335,"./plugins/collapseGroups.js":336,"./plugins/convertColors.js":337,"./plugins/convertEllipseToCircle.js":338,"./plugins/convertPathData.js":339,"./plugins/convertShapeToPath.js":340,"./plugins/convertStyleToAttrs.js":341,"./plugins/convertTransform.js":342,"./plugins/default.js":343,"./plugins/inlineStyles.js":344,"./plugins/mergePaths.js":345,"./plugins/mergeStyles.js":346,"./plugins/minifyStyles.js":347,"./plugins/moveElemsAttrsToGroup.js":348,"./plugins/moveGroupAttrsToElems.js":349,"./plugins/prefixIds.js":350,"./plugins/removeAttributesBySelector.js":351,"./plugins/removeAttrs.js":352,"./plugins/removeComments.js":353,"./plugins/removeDesc.js":354,"./plugins/removeDimensions.js":355,"./plugins/removeDoctype.js":356,"./plugins/removeEditorsNSData.js":357,"./plugins/removeElementsByAttr.js":358,"./plugins/removeEmptyAttrs.js":359,"./plugins/removeEmptyContainers.js":360,"./plugins/removeEmptyText.js":361,"./plugins/removeHiddenElems.js":362,"./plugins/removeMetadata.js":363,"./plugins/removeNonInheritableGroupAttrs.js":364,"./plugins/removeOffCanvasPaths.js":365,"./plugins/removeRasterImages.js":366,"./plugins/removeScriptElement.js":367,"./plugins/removeStyleElement.js":368,"./plugins/removeTitle.js":369,"./plugins/removeUnknownsAndDefaults.js":370,"./plugins/removeUnusedNS.js":371,"./plugins/removeUselessDefs.js":372,"./plugins/removeUselessStrokeAndFill.js":373,"./plugins/removeViewBox.js":374,"./plugins/removeXMLNS.js":375,"./plugins/removeXMLProcInst.js":376,"./plugins/reusePaths.js":377,"./plugins/safe.js":378,"./plugins/sortAttrs.js":379,"./plugins/sortDefsChildren.js":380}],321:[function(require,module,exports){ +},{"./plugins/addAttributesToSVGElement.js":328,"./plugins/addClassesToSVGElement.js":329,"./plugins/cleanupAttrs.js":331,"./plugins/cleanupEnableBackground.js":332,"./plugins/cleanupIds.js":333,"./plugins/cleanupListOfValues.js":334,"./plugins/cleanupNumericValues.js":335,"./plugins/collapseGroups.js":336,"./plugins/convertColors.js":337,"./plugins/convertEllipseToCircle.js":338,"./plugins/convertPathData.js":339,"./plugins/convertShapeToPath.js":340,"./plugins/convertStyleToAttrs.js":341,"./plugins/convertTransform.js":342,"./plugins/default.js":343,"./plugins/inlineStyles.js":344,"./plugins/mergePaths.js":345,"./plugins/mergeStyles.js":346,"./plugins/minifyStyles.js":347,"./plugins/moveElemsAttrsToGroup.js":348,"./plugins/moveGroupAttrsToElems.js":349,"./plugins/prefixIds.js":350,"./plugins/removeAttributesBySelector.js":351,"./plugins/removeAttrs.js":352,"./plugins/removeComments.js":353,"./plugins/removeDesc.js":354,"./plugins/removeDimensions.js":355,"./plugins/removeDoctype.js":356,"./plugins/removeEditorsNSData.js":357,"./plugins/removeElementsByAttr.js":358,"./plugins/removeEmptyAttrs.js":359,"./plugins/removeEmptyContainers.js":360,"./plugins/removeEmptyText.js":361,"./plugins/removeHiddenElems.js":362,"./plugins/removeMetadata.js":363,"./plugins/removeNonInheritableGroupAttrs.js":364,"./plugins/removeOffCanvasPaths.js":365,"./plugins/removeRasterImages.js":366,"./plugins/removeScriptElement.js":367,"./plugins/removeStyleElement.js":368,"./plugins/removeTitle.js":369,"./plugins/removeUnknownsAndDefaults.js":370,"./plugins/removeUnusedNS.js":371,"./plugins/removeUselessDefs.js":372,"./plugins/removeUselessStrokeAndFill.js":373,"./plugins/removeViewBox.js":374,"./plugins/removeXMLNS.js":375,"./plugins/removeXMLProcInst.js":376,"./plugins/reusePaths.js":377,"./plugins/safe.js":378,"./plugins/safeAndFast.js":379,"./plugins/sortAttrs.js":380,"./plugins/sortDefsChildren.js":381}],321:[function(require,module,exports){ 'use strict'; const isTag = (node) => { @@ -30102,7 +30103,7 @@ const stringifyPathData = ({ pathData, precision, disableSpaceAfterFlags }) => { }; exports.stringifyPathData = stringifyPathData; -},{"./tools.js":383}],324:[function(require,module,exports){ +},{"./tools.js":384}],324:[function(require,module,exports){ 'use strict'; const { builtin } = require('./builtin.js'); @@ -33826,7 +33827,7 @@ const applyMatrixToPathData = (pathData, matrix) => { } }; -},{"../style.js":382,"../tools.js":383,"./_collections.js":325,"./_path.js":326,"./_transforms.js":327}],331:[function(require,module,exports){ +},{"../style.js":383,"../tools.js":384,"./_collections.js":325,"./_path.js":326,"./_transforms.js":327}],331:[function(require,module,exports){ 'use strict'; exports.name = 'cleanupAttrs'; @@ -33948,7 +33949,7 @@ exports.fn = (root) => { }; }; -},{"../xast.js":384}],333:[function(require,module,exports){ +},{"../xast.js":385}],333:[function(require,module,exports){ 'use strict'; const { visitSkip } = require('../xast.js'); @@ -34207,7 +34208,7 @@ exports.fn = (_root, params) => { }; }; -},{"../xast.js":384,"./_collections.js":325}],334:[function(require,module,exports){ +},{"../xast.js":385,"./_collections.js":325}],334:[function(require,module,exports){ 'use strict'; const { removeLeadingZero } = require('../tools.js'); @@ -34345,7 +34346,7 @@ exports.fn = (_root, params) => { }; }; -},{"../tools.js":383}],335:[function(require,module,exports){ +},{"../tools.js":384}],335:[function(require,module,exports){ 'use strict'; const { removeLeadingZero } = require('../tools.js'); @@ -34451,7 +34452,7 @@ exports.fn = (_root, params) => { }; }; -},{"../tools.js":383}],336:[function(require,module,exports){ +},{"../tools.js":384}],336:[function(require,module,exports){ 'use strict'; const { inheritableAttrs, elemsGroups } = require('./_collections.js'); @@ -35838,7 +35839,7 @@ function data2Path(params, pathData) { }, ''); } -},{"../style.js":382,"../tools.js":383,"../xast.js":384,"./_collections.js":325,"./_path.js":326,"./applyTransforms.js":330}],340:[function(require,module,exports){ +},{"../style.js":383,"../tools.js":384,"../xast.js":385,"./_collections.js":325,"./_path.js":326,"./applyTransforms.js":330}],340:[function(require,module,exports){ 'use strict'; const { stringifyPathData } = require('../path.js'); @@ -36004,7 +36005,7 @@ exports.fn = (root, params) => { }; }; -},{"../path.js":323,"../xast.js":384}],341:[function(require,module,exports){ +},{"../path.js":323,"../xast.js":385}],341:[function(require,module,exports){ 'use strict'; const { attrsGroups } = require('./_collections'); @@ -36506,7 +36507,7 @@ const smartRound = (precision, data) => { return data; }; -},{"../tools.js":383,"./_transforms.js":327}],343:[function(require,module,exports){ +},{"../tools.js":384,"./_transforms.js":327}],343:[function(require,module,exports){ 'use strict'; const { createPreset } = require('../tools.js'); @@ -36590,7 +36591,7 @@ const presetDefault = createPreset({ module.exports = presetDefault; -},{"../tools.js":383,"./cleanupAttrs.js":331,"./cleanupEnableBackground.js":332,"./cleanupIds.js":333,"./cleanupNumericValues.js":335,"./collapseGroups.js":336,"./convertColors.js":337,"./convertEllipseToCircle.js":338,"./convertPathData.js":339,"./convertShapeToPath.js":340,"./convertTransform.js":342,"./inlineStyles.js":344,"./mergePaths.js":345,"./mergeStyles.js":346,"./minifyStyles.js":347,"./moveElemsAttrsToGroup.js":348,"./moveGroupAttrsToElems.js":349,"./removeComments.js":353,"./removeDesc.js":354,"./removeDoctype.js":356,"./removeEditorsNSData.js":357,"./removeEmptyAttrs.js":359,"./removeEmptyContainers.js":360,"./removeEmptyText.js":361,"./removeHiddenElems.js":362,"./removeMetadata.js":363,"./removeNonInheritableGroupAttrs.js":364,"./removeTitle.js":369,"./removeUnknownsAndDefaults.js":370,"./removeUnusedNS.js":371,"./removeUselessDefs.js":372,"./removeUselessStrokeAndFill.js":373,"./removeViewBox.js":374,"./removeXMLProcInst.js":376,"./sortAttrs.js":379,"./sortDefsChildren.js":380}],344:[function(require,module,exports){ +},{"../tools.js":384,"./cleanupAttrs.js":331,"./cleanupEnableBackground.js":332,"./cleanupIds.js":333,"./cleanupNumericValues.js":335,"./collapseGroups.js":336,"./convertColors.js":337,"./convertEllipseToCircle.js":338,"./convertPathData.js":339,"./convertShapeToPath.js":340,"./convertTransform.js":342,"./inlineStyles.js":344,"./mergePaths.js":345,"./mergeStyles.js":346,"./minifyStyles.js":347,"./moveElemsAttrsToGroup.js":348,"./moveGroupAttrsToElems.js":349,"./removeComments.js":353,"./removeDesc.js":354,"./removeDoctype.js":356,"./removeEditorsNSData.js":357,"./removeEmptyAttrs.js":359,"./removeEmptyContainers.js":360,"./removeEmptyText.js":361,"./removeHiddenElems.js":362,"./removeMetadata.js":363,"./removeNonInheritableGroupAttrs.js":364,"./removeTitle.js":369,"./removeUnknownsAndDefaults.js":370,"./removeUnusedNS.js":371,"./removeUselessDefs.js":372,"./removeUselessStrokeAndFill.js":373,"./removeViewBox.js":374,"./removeXMLProcInst.js":376,"./sortAttrs.js":380,"./sortDefsChildren.js":381}],344:[function(require,module,exports){ 'use strict'; const csstree = require('css-tree'); @@ -36937,7 +36938,7 @@ exports.fn = (root, params) => { }; }; -},{"../xast.js":384,"css-tree":25,"csso":138}],345:[function(require,module,exports){ +},{"../xast.js":385,"css-tree":25,"csso":138}],345:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -37035,7 +37036,7 @@ exports.fn = (root, params) => { }; }; -},{"../style.js":382,"../xast.js":384,"./_path.js":326}],346:[function(require,module,exports){ +},{"../style.js":383,"../xast.js":385,"./_path.js":326}],346:[function(require,module,exports){ 'use strict'; const { visitSkip, detachNodeFromParent } = require('../xast.js'); @@ -37119,7 +37120,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],347:[function(require,module,exports){ +},{"../xast.js":385}],347:[function(require,module,exports){ 'use strict'; const csso = require('csso'); @@ -37364,7 +37365,7 @@ exports.fn = (root) => { }; }; -},{"../xast.js":384,"./_collections.js":325}],349:[function(require,module,exports){ +},{"../xast.js":385,"./_collections.js":325}],349:[function(require,module,exports){ 'use strict'; const { pathElems, referencesProps } = require('./_collections.js'); @@ -37742,7 +37743,7 @@ exports.fn = (root, params) => { return {}; }; -},{"../xast.js":384}],352:[function(require,module,exports){ +},{"../xast.js":385}],352:[function(require,module,exports){ 'use strict'; exports.name = 'removeAttrs'; @@ -37924,7 +37925,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],354:[function(require,module,exports){ +},{"../xast.js":385}],354:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -37963,7 +37964,7 @@ exports.fn = (root, params) => { }; }; -},{"../xast.js":384}],355:[function(require,module,exports){ +},{"../xast.js":385}],355:[function(require,module,exports){ 'use strict'; exports.name = 'removeDimensions'; @@ -38046,7 +38047,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],357:[function(require,module,exports){ +},{"../xast.js":385}],357:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38110,7 +38111,7 @@ exports.fn = (_root, params) => { }; }; -},{"../xast.js":384,"./_collections.js":325}],358:[function(require,module,exports){ +},{"../xast.js":385,"./_collections.js":325}],358:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38183,7 +38184,7 @@ exports.fn = (root, params) => { }; }; -},{"../xast.js":384}],359:[function(require,module,exports){ +},{"../xast.js":385}],359:[function(require,module,exports){ 'use strict'; const { attrsGroups } = require('./_collections.js'); @@ -38270,7 +38271,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384,"./_collections.js":325}],361:[function(require,module,exports){ +},{"../xast.js":385,"./_collections.js":325}],361:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38321,7 +38322,7 @@ exports.fn = (root, params) => { }; }; -},{"../xast.js":384}],362:[function(require,module,exports){ +},{"../xast.js":385}],362:[function(require,module,exports){ 'use strict'; const { @@ -38631,7 +38632,7 @@ exports.fn = (root, params) => { }; }; -},{"../path.js":323,"../style.js":382,"../xast.js":384}],363:[function(require,module,exports){ +},{"../path.js":323,"../style.js":383,"../xast.js":385}],363:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38658,7 +38659,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],364:[function(require,module,exports){ +},{"../xast.js":385}],364:[function(require,module,exports){ 'use strict'; const { @@ -38815,7 +38816,7 @@ exports.fn = () => { }; }; -},{"../path.js":323,"../xast.js":384,"./_path.js":326}],366:[function(require,module,exports){ +},{"../path.js":323,"../xast.js":385,"./_path.js":326}],366:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38846,7 +38847,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],367:[function(require,module,exports){ +},{"../xast.js":385}],367:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38873,7 +38874,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],368:[function(require,module,exports){ +},{"../xast.js":385}],368:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38900,7 +38901,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],369:[function(require,module,exports){ +},{"../xast.js":385}],369:[function(require,module,exports){ 'use strict'; const { detachNodeFromParent } = require('../xast.js'); @@ -38927,7 +38928,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],370:[function(require,module,exports){ +},{"../xast.js":385}],370:[function(require,module,exports){ 'use strict'; const { visitSkip, detachNodeFromParent } = require('../xast.js'); @@ -39135,7 +39136,7 @@ exports.fn = (root, params) => { }; }; -},{"../style.js":382,"../xast.js":384,"./_collections":325}],371:[function(require,module,exports){ +},{"../style.js":383,"../xast.js":385,"./_collections":325}],371:[function(require,module,exports){ 'use strict'; exports.name = 'removeUnusedNS'; @@ -39252,7 +39253,7 @@ const collectUsefulNodes = (node, usefulNodes) => { } }; -},{"../xast.js":384,"./_collections.js":325}],373:[function(require,module,exports){ +},{"../xast.js":385,"./_collections.js":325}],373:[function(require,module,exports){ 'use strict'; const { visit, visitSkip, detachNodeFromParent } = require('../xast.js'); @@ -39390,7 +39391,7 @@ exports.fn = (root, params) => { }; }; -},{"../style.js":382,"../xast.js":384,"./_collections.js":325}],374:[function(require,module,exports){ +},{"../style.js":383,"../xast.js":385,"./_collections.js":325}],374:[function(require,module,exports){ 'use strict'; exports.name = 'removeViewBox'; @@ -39497,7 +39498,7 @@ exports.fn = () => { }; }; -},{"../xast.js":384}],377:[function(require,module,exports){ +},{"../xast.js":385}],377:[function(require,module,exports){ 'use strict'; exports.name = 'reusePaths'; @@ -39678,7 +39679,72 @@ const presetSafe = createPreset({ module.exports = presetSafe; -},{"../tools.js":383,"./cleanupAttrs.js":331,"./cleanupEnableBackground.js":332,"./cleanupIds.js":333,"./cleanupNumericValues.js":335,"./collapseGroups.js":336,"./convertColors.js":337,"./convertEllipseToCircle.js":338,"./convertPathData.js":339,"./convertTransform.js":342,"./inlineStyles.js":344,"./mergePaths.js":345,"./mergeStyles.js":346,"./minifyStyles.js":347,"./removeComments.js":353,"./removeDesc.js":354,"./removeDoctype.js":356,"./removeEditorsNSData.js":357,"./removeEmptyAttrs.js":359,"./removeEmptyContainers.js":360,"./removeEmptyText.js":361,"./removeHiddenElems.js":362,"./removeMetadata.js":363,"./removeNonInheritableGroupAttrs.js":364,"./removeTitle.js":369,"./removeUnknownsAndDefaults.js":370,"./removeUnusedNS.js":371,"./removeUselessDefs.js":372,"./removeUselessStrokeAndFill.js":373,"./removeViewBox.js":374,"./removeXMLProcInst.js":376,"./sortDefsChildren.js":380}],379:[function(require,module,exports){ +},{"../tools.js":384,"./cleanupAttrs.js":331,"./cleanupEnableBackground.js":332,"./cleanupIds.js":333,"./cleanupNumericValues.js":335,"./collapseGroups.js":336,"./convertColors.js":337,"./convertEllipseToCircle.js":338,"./convertPathData.js":339,"./convertTransform.js":342,"./inlineStyles.js":344,"./mergePaths.js":345,"./mergeStyles.js":346,"./minifyStyles.js":347,"./removeComments.js":353,"./removeDesc.js":354,"./removeDoctype.js":356,"./removeEditorsNSData.js":357,"./removeEmptyAttrs.js":359,"./removeEmptyContainers.js":360,"./removeEmptyText.js":361,"./removeHiddenElems.js":362,"./removeMetadata.js":363,"./removeNonInheritableGroupAttrs.js":364,"./removeTitle.js":369,"./removeUnknownsAndDefaults.js":370,"./removeUnusedNS.js":371,"./removeUselessDefs.js":372,"./removeUselessStrokeAndFill.js":373,"./removeViewBox.js":374,"./removeXMLProcInst.js":376,"./sortDefsChildren.js":381}],379:[function(require,module,exports){ +'use strict'; + +const { createPreset } = require('../tools.js'); + +const removeDoctype = require('./removeDoctype.js'); +const removeXMLProcInst = require('./removeXMLProcInst.js'); +const removeComments = require('./removeComments.js'); +const removeMetadata = require('./removeMetadata.js'); +const removeEditorsNSData = require('./removeEditorsNSData.js'); +const cleanupAttrs = require('./cleanupAttrs.js'); +const mergeStyles = require('./mergeStyles.js'); +const minifyStyles = require('./minifyStyles.js'); +const cleanupIds = require('./cleanupIds.js'); +const removeUselessDefs = require('./removeUselessDefs.js'); +const cleanupNumericValues = require('./cleanupNumericValues.js'); +const convertColors = require('./convertColors.js'); +const removeUnknownsAndDefaults = require('./removeUnknownsAndDefaults.js'); +const removeNonInheritableGroupAttrs = require('./removeNonInheritableGroupAttrs.js'); +const removeUselessStrokeAndFill = require('./removeUselessStrokeAndFill.js'); +const removeViewBox = require('./removeViewBox.js'); +const cleanupEnableBackground = require('./cleanupEnableBackground.js'); +const removeHiddenElems = require('./removeHiddenElems.js'); +const removeEmptyText = require('./removeEmptyText.js'); +const collapseGroups = require('./collapseGroups.js'); +const removeEmptyAttrs = require('./removeEmptyAttrs.js'); +const removeEmptyContainers = require('./removeEmptyContainers.js'); +const mergePaths = require('./mergePaths.js'); +const removeUnusedNS = require('./removeUnusedNS.js'); +const sortDefsChildren = require('./sortDefsChildren.js'); +const removeTitle = require('./removeTitle.js'); +const removeDesc = require('./removeDesc.js'); + +const presetSafe = createPreset({ + name: 'safeAndFastPreset', + plugins: [ + removeDoctype, + removeXMLProcInst, + removeComments, + removeMetadata, + removeEditorsNSData, + cleanupAttrs, + mergeStyles, + cleanupIds, + removeUselessDefs, + cleanupNumericValues, + convertColors, + removeUnknownsAndDefaults, + removeNonInheritableGroupAttrs, + removeUselessStrokeAndFill, + removeViewBox, + cleanupEnableBackground, + removeHiddenElems, + removeEmptyText, + collapseGroups, + removeEmptyAttrs, + removeEmptyContainers, + removeUnusedNS, + removeTitle, + removeDesc, + ], +}); + +module.exports = presetSafe; + +},{"../tools.js":384,"./cleanupAttrs.js":331,"./cleanupEnableBackground.js":332,"./cleanupIds.js":333,"./cleanupNumericValues.js":335,"./collapseGroups.js":336,"./convertColors.js":337,"./mergePaths.js":345,"./mergeStyles.js":346,"./minifyStyles.js":347,"./removeComments.js":353,"./removeDesc.js":354,"./removeDoctype.js":356,"./removeEditorsNSData.js":357,"./removeEmptyAttrs.js":359,"./removeEmptyContainers.js":360,"./removeEmptyText.js":361,"./removeHiddenElems.js":362,"./removeMetadata.js":363,"./removeNonInheritableGroupAttrs.js":364,"./removeTitle.js":369,"./removeUnknownsAndDefaults.js":370,"./removeUnusedNS.js":371,"./removeUselessDefs.js":372,"./removeUselessStrokeAndFill.js":373,"./removeViewBox.js":374,"./removeXMLProcInst.js":376,"./sortDefsChildren.js":381}],380:[function(require,module,exports){ 'use strict'; exports.name = 'sortAttrs'; @@ -39778,7 +39844,7 @@ exports.fn = (_root, params) => { }; }; -},{}],380:[function(require,module,exports){ +},{}],381:[function(require,module,exports){ 'use strict'; exports.name = 'sortDefsChildren'; @@ -39836,7 +39902,7 @@ exports.fn = () => { }; }; -},{}],381:[function(require,module,exports){ +},{}],382:[function(require,module,exports){ 'use strict'; const { textElems } = require('./plugins/_collections.js'); @@ -40070,7 +40136,7 @@ const stringifyText = (node, config, state) => { ); }; -},{"./plugins/_collections.js":325}],382:[function(require,module,exports){ +},{"./plugins/_collections.js":325}],383:[function(require,module,exports){ 'use strict'; const csstree = require('css-tree'); @@ -40300,7 +40366,7 @@ const computeStyle = (stylesheet, node) => { }; exports.computeStyle = computeStyle; -},{"./plugins/_collections.js":325,"./xast.js":384,"css-tree":25,"csso":138}],383:[function(require,module,exports){ +},{"./plugins/_collections.js":325,"./xast.js":385,"css-tree":25,"csso":138}],384:[function(require,module,exports){ (function (Buffer){(function (){ 'use strict'; @@ -40455,7 +40521,7 @@ exports.invokePlugins = invokePlugins; exports.createPreset = createPreset; }).call(this)}).call(this,require("buffer").Buffer) -},{"./xast.js":384,"buffer":4}],384:[function(require,module,exports){ +},{"./xast.js":385,"buffer":4}],385:[function(require,module,exports){ 'use strict'; const { selectAll, selectOne, is } = require('css-select'); From 2fc6290c8f83176659cf1225580ae09ac3fd04e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 15 Dec 2023 13:53:53 +0100 Subject: [PATCH 31/35] :bug: Fix invalid frame-id when adding shape to copy --- common/src/app/common/types/shape_tree.cljc | 17 ++++++++++------- .../main/data/workspace/libraries_helpers.cljs | 6 +++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 928a5ed664..6cdf951b51 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -354,21 +354,24 @@ the order of the children of each parent." ([object parent-id objects] - (clone-object object parent-id objects (fn [object _] object) (fn [object _] object) nil false nil)) + (clone-object object parent-id objects (fn [object _] object) (fn [object _] object) nil false nil objects)) ([object parent-id objects update-new-object] - (clone-object object parent-id objects update-new-object (fn [object _] object) nil false nil)) + (clone-object object parent-id objects update-new-object (fn [object _] object) nil false nil objects)) ([object parent-id objects update-new-object update-original-object] - (clone-object object parent-id objects update-new-object update-original-object nil false nil)) + (clone-object object parent-id objects update-new-object update-original-object nil false nil objects)) ([object parent-id objects update-new-object update-original-object force-id] - (clone-object object parent-id objects update-new-object update-original-object force-id false nil)) + (clone-object object parent-id objects update-new-object update-original-object force-id false nil objects)) ([object parent-id objects update-new-object update-original-object force-id keep-ids?] - (clone-object object parent-id objects update-new-object update-original-object force-id keep-ids? nil)) + (clone-object object parent-id objects update-new-object update-original-object force-id keep-ids? nil objects)) ([object parent-id objects update-new-object update-original-object force-id keep-ids? frame-id] + (clone-object object parent-id objects update-new-object update-original-object force-id keep-ids? frame-id objects)) + + ([object parent-id objects update-new-object update-original-object force-id keep-ids? frame-id dest-objects] (let [new-id (cond (some? force-id) force-id keep-ids? (:id object) @@ -378,11 +381,11 @@ ;; or the parent's frame-id otherwise. Only for the first cloned shapes. In recursive calls ;; this is not needed. frame-id (cond - (and (nil? frame-id) (cfh/frame-shape? objects parent-id)) + (and (nil? frame-id) (cfh/frame-shape? dest-objects parent-id)) parent-id (nil? frame-id) - (dm/get-in objects [parent-id :frame-id]) + (dm/get-in dest-objects [parent-id :frame-id] uuid/zero) :else frame-id)] diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 11aa8558fd..e5150b1ca2 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -980,7 +980,11 @@ (:id parent-shape) (get component-page :objects) update-new-shape - update-original-shape) + update-original-shape + nil + false + nil + (:objects container)) add-obj-change (fn [changes shape'] (update changes :redo-changes conj From f49cf0b6ae052f17e3e9dd6c244a20ec440076f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 15 Dec 2023 14:36:47 +0100 Subject: [PATCH 32/35] :lipstick: Style changes on clone-object function (now clone-shape) --- common/src/app/common/types/container.cljc | 23 +-- common/src/app/common/types/shape_tree.cljc | 133 +++++++++--------- .../data/workspace/libraries_helpers.cljs | 38 +++-- 3 files changed, 94 insertions(+), 100 deletions(-) diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index a7f060391e..3d5cb31c43 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -255,7 +255,11 @@ (dissoc :component-root))) [new-root-shape new-shapes updated-shapes] - (ctst/clone-object shape nil objects update-new-shape update-original-shape) + (ctst/clone-shape shape + nil + objects + :update-new-shape update-new-shape + :update-original-shape update-original-shape) ;; If frame-id points to a shape inside the component, remap it to the ;; corresponding new frame shape. If not, set it to nil. @@ -339,15 +343,14 @@ (dissoc :component-root)))) [new-shape new-shapes _] - (ctst/clone-object component-shape - frame-id - (if components-v2 (:objects component-page) (:objects component)) - update-new-shape - (fn [object _] object) - force-id - keep-ids? - frame-id) - + (ctst/clone-shape component-shape + frame-id + (if components-v2 (:objects component-page) (:objects component)) + :update-new-shape update-new-shape + :force-id force-id + :keep-ids? keep-ids? + :frame-id frame-id + :dest-objects (:objects container)) ;; Fix empty parent-id and remap all grid cells to the new ids. remap-ids diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 6cdf951b51..ab6f08e41b 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -342,94 +342,89 @@ [frame] (not (mth/almost-zero? (:rotation frame 0)))) -(defn clone-object - "Gets a copy of the object and all its children, with new ids and with +(defn clone-shape + "Gets a copy of the shape and all its children, with new ids and with the parent-children links correctly set. Admits functions to make - more transformations to the cloned objects and the original ones. + more transformations to the cloned shapes and the original ones. - Returns the cloned object, the list of all new objects (including - the cloned one), and possibly a list of original objects modified. + Returns the cloned shape, the list of all new shapes (including + the cloned one), and possibly a list of original shapes modified. - The list of objects are returned in tree traversal order, respecting + The list of shapes are returned in tree traversal order, respecting the order of the children of each parent." - - ([object parent-id objects] - (clone-object object parent-id objects (fn [object _] object) (fn [object _] object) nil false nil objects)) - - ([object parent-id objects update-new-object] - (clone-object object parent-id objects update-new-object (fn [object _] object) nil false nil objects)) - - ([object parent-id objects update-new-object update-original-object] - (clone-object object parent-id objects update-new-object update-original-object nil false nil objects)) - - ([object parent-id objects update-new-object update-original-object force-id] - (clone-object object parent-id objects update-new-object update-original-object force-id false nil objects)) - - ([object parent-id objects update-new-object update-original-object force-id keep-ids?] - (clone-object object parent-id objects update-new-object update-original-object force-id keep-ids? nil objects)) - - ([object parent-id objects update-new-object update-original-object force-id keep-ids? frame-id] - (clone-object object parent-id objects update-new-object update-original-object force-id keep-ids? frame-id objects)) - - ([object parent-id objects update-new-object update-original-object force-id keep-ids? frame-id dest-objects] - (let [new-id (cond - (some? force-id) force-id - keep-ids? (:id object) - :else (uuid/next)) + [shape parent-id objects & {:keys [update-new-shape update-original-shape force-id keep-ids? frame-id dest-objects] + :or {update-new-shape (fn [shape _] shape) + update-original-shape (fn [shape _] shape) + force-id nil + keep-ids? false + frame-id nil + dest-objects objects}}] + (let [new-id (cond + (some? force-id) force-id + keep-ids? (:id shape) + :else (uuid/next)) ;; Assign the correct frame-id for the given parent. It's the parent-id (if parent is frame) ;; or the parent's frame-id otherwise. Only for the first cloned shapes. In recursive calls ;; this is not needed. - frame-id (cond - (and (nil? frame-id) (cfh/frame-shape? dest-objects parent-id)) - parent-id + frame-id (cond + (and (nil? frame-id) (cfh/frame-shape? dest-objects parent-id)) + parent-id - (nil? frame-id) - (dm/get-in dest-objects [parent-id :frame-id] uuid/zero) + (nil? frame-id) + (dm/get-in dest-objects [parent-id :frame-id] uuid/zero) - :else - frame-id)] + :else + frame-id)] - (loop [child-ids (seq (:shapes object)) - new-direct-children [] - new-children [] - updated-children []] + (loop [child-ids (seq (:shapes shape)) + new-direct-children [] + new-children [] + updated-children []] - (if (empty? child-ids) - (let [new-object (cond-> object - :always - (assoc :id new-id - :parent-id parent-id - :frame-id frame-id) + (if (empty? child-ids) + (let [new-shape (cond-> shape + :always + (assoc :id new-id + :parent-id parent-id + :frame-id frame-id) - (some? (:shapes object)) - (assoc :shapes (mapv :id new-direct-children))) + (some? (:shapes shape)) + (assoc :shapes (mapv :id new-direct-children))) - new-object (update-new-object new-object object) - new-objects (into [new-object] new-children) + new-shape (update-new-shape new-shape shape) + new-shapes (into [new-shape] new-children) - updated-object (update-original-object object new-object) - updated-objects (if (identical? object updated-object) - updated-children - (into [updated-object] updated-children))] + updated-shape (update-original-shape shape new-shape) + updated-shapes (if (identical? shape updated-shape) + updated-children + (into [updated-shape] updated-children))] - [new-object new-objects updated-objects]) + [new-shape new-shapes updated-shapes]) - (let [child-id (first child-ids) - child (get objects child-id) - _ (dm/assert! (some? child)) - frame-id-child (if (cfh/frame-shape? object) - new-id - frame-id) + (let [child-id (first child-ids) + child (get objects child-id) + _ (dm/assert! (some? child)) + frame-id-child (if (cfh/frame-shape? shape) + new-id + frame-id) - [new-child new-child-objects updated-child-objects] - (clone-object child new-id objects update-new-object update-original-object nil keep-ids? frame-id-child)] + [new-child new-child-shapes updated-child-shapes] + (clone-shape child + new-id + objects + :update-new-shape update-new-shape + :update-original-shape update-original-shape + :force-id nil + :keep-ids? keep-ids? + :frame-id frame-id-child + :dest-objects dest-objects)] - (recur - (next child-ids) - (into new-direct-children [new-child]) - (into new-children new-child-objects) - (into updated-children updated-child-objects)))))))) + (recur + (next child-ids) + (into new-direct-children [new-child]) + (into new-children new-child-shapes) + (into updated-children updated-child-shapes))))))) (defn generate-shape-grid "Generate a sequence of positions that lays out the list of diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index e5150b1ca2..f9854062fe 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -98,11 +98,11 @@ (gsh/move delta))) [new-instance-shape new-instance-shapes _] - (ctst/clone-object main-instance-shape - (:parent-id main-instance-shape) - (:objects main-instance-page) - update-new-shape - update-original-shape) + (ctst/clone-shape main-instance-shape + (:parent-id main-instance-shape) + (:objects main-instance-page) + :update-new-shape update-new-shape + :update-original-shape update-original-shape) remap-frame (fn [shape] @@ -134,10 +134,9 @@ (let [component-root (d/seek #(nil? (:parent-id %)) (vals (:objects component))) [new-component-shape new-component-shapes _] - (ctst/clone-object component-root - nil - (get component :objects) - identity)] + (ctst/clone-shape component-root + nil + (get component :objects))] [new-component-shape new-component-shapes nil nil])))) @@ -976,15 +975,12 @@ original-shape) [_ new-shapes _] - (ctst/clone-object component-shape + (ctst/clone-shape component-shape (:id parent-shape) (get component-page :objects) - update-new-shape - update-original-shape - nil - false - nil - (:objects container)) + :update-new-shape update-new-shape + :update-original-shape update-original-shape + :dest-objects (get container :objects)) add-obj-change (fn [changes shape'] (update changes :redo-changes conj @@ -1042,11 +1038,11 @@ original-shape)) [_new-shape new-shapes updated-shapes] - (ctst/clone-object shape - (:id component-parent-shape) - (get page :objects) - update-new-shape - update-original-shape) + (ctst/clone-shape shape + (:id component-parent-shape) + (get page :objects) + :update-new-shape update-new-shape + :update-original-shape update-original-shape) add-obj-change (fn [changes shape'] (update changes :redo-changes conj From e3ed198ba118c4147162dc0319607c5e83e73b3d Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 4 Jan 2024 15:15:12 +0100 Subject: [PATCH 33/35] :lipstick: Redesign debug panel --- .../app/main/ui/workspace/sidebar/debug.cljs | 28 +++++---- .../app/main/ui/workspace/sidebar/debug.scss | 59 +++++++++++++++++++ 2 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 frontend/src/app/main/ui/workspace/sidebar/debug.scss diff --git a/frontend/src/app/main/ui/workspace/sidebar/debug.cljs b/frontend/src/app/main/ui/workspace/sidebar/debug.cljs index 5d7932a898..71adc0d998 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/debug.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/debug.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.debug + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.main.data.workspace :as dw] @@ -24,26 +25,27 @@ (dbg/toggle! option) (js* "app.main.reinit()"))) - on-close + handle-close (mf/use-fn (fn [] (st/emit! (dw/remove-layout-flag :debug-panel))))] - [:div.debug-panel - [:div.debug-panel-header - [:div.debug-panel-close-button - {:on-click on-close} i/close] - [:div.debug-panel-title "Debugging tools"]] - [:div.debug-panel-inner + [:div {:class (stl/css :debug-panel)} + [:div {:class (stl/css :panel-title)} + [:span "Debugging tools"] + [:div {:class (stl/css :close-button) :on-click handle-close} + i/close-refactor]] + + [:div {:class (stl/css :debug-panel-inner)} (for [option (sort-by d/name dbg/options)] - [:div.debug-option {:key (d/name option) - :on-click #(on-toggle-enabled % option)} + [:div {:class (stl/css :checkbox-wrapper)} + [:span {:class (stl/css-case :checkbox-icon true :global/checked (dbg/enabled? option)) + :on-click #(on-toggle-enabled % option)} + (when (dbg/enabled? option) i/status-tick-refactor)] + [:input {:type "checkbox" :id (d/name option) + :key (d/name option) :on-change #(on-toggle-enabled % option) :checked (dbg/enabled? option)}] - [:div.field.check - (if (dbg/enabled? option) - [:span.checked i/checkbox-checked] - [:span.unchecked i/checkbox-unchecked])] [:label {:for (d/name option)} (d/name option)]])]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/debug.scss b/frontend/src/app/main/ui/workspace/sidebar/debug.scss new file mode 100644 index 0000000000..96364d88ee --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/debug.scss @@ -0,0 +1,59 @@ +// 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 + +@use "common/refactor/common-refactor.scss" as *; + +.debug-panel { + display: flex; + flex-direction: column; + background-color: var(--panel-background-color); +} + +.panel-title { + @include flexCenter; + @include tabTitleTipography; + position: relative; + height: $s-32; + min-height: $s-32; + margin: $s-8 $s-8 0 $s-8; + border-radius: $br-8; + background-color: var(--panel-title-background-color); + + span { + @include flexCenter; + flex-grow: 1; + color: var(--title-foreground-color-hover); + } +} + +.close-button { + @extend .button-tertiary; + position: absolute; + right: $s-2; + top: $s-2; + height: $s-28; + width: $s-28; + border-radius: $br-6; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} + +.checkbox-wrapper { + @extend .input-checkbox; + height: $s-32; + padding: 0; +} + +.checkbox-icon { + @extend .checkbox-icon; + cursor: pointer; +} + +.debug-panel-inner { + padding: $s-16 $s-8; +} From 9e52cdb75ed93453c32d0d1f834866977e22b21b Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 4 Jan 2024 15:16:43 +0100 Subject: [PATCH 34/35] :bug: Change behavior of auto cells --- .../src/app/common/files/shapes_helpers.cljc | 4 +- common/src/app/common/types/shape/layout.cljc | 111 ++++++++++++++---- .../src/app/main/data/workspace/changes.cljs | 3 + .../app/main/data/workspace/selection.cljs | 1 - .../app/main/data/workspace/shape_layout.cljs | 7 +- .../app/main/data/workspace/transforms.cljs | 6 +- .../viewport/grid_layout_editor.cljs | 24 ++++ frontend/src/app/util/debug.cljs | 3 + frontend/translations/en.po | 2 +- 9 files changed, 129 insertions(+), 32 deletions(-) diff --git a/common/src/app/common/files/shapes_helpers.cljc b/common/src/app/common/files/shapes_helpers.cljc index 3a375072f9..8a656886f1 100644 --- a/common/src/app/common/files/shapes_helpers.cljc +++ b/common/src/app/common/files/shapes_helpers.cljc @@ -50,8 +50,8 @@ (pcb/update-shapes ordered-indexes #(cond-> % (cfh/frame-shape? %) (assoc :hide-in-viewer true))) (pcb/change-parent frame-id to-move-shapes 0) (cond-> (ctl/grid-layout? objects frame-id) - (pcb/update-shapes [frame-id] ctl/assign-cells {:with-objects? true})) - (pcb/reorder-grid-children [frame-id])) + (-> (pcb/update-shapes [frame-id] ctl/assign-cells {:with-objects? true}) + (pcb/reorder-grid-children [frame-id])))) changes))) (defn prepare-create-artboard-from-selection diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 08645a098a..745cd941e4 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -628,23 +628,36 @@ (filter #(> (get % prop-span) 1)) (reduce (fn [parent cell] - (let [changed-cells + (let [area? (= :area (:position cell)) + changed-cells (cond ;; New track at the beginning (= (get cell prop) (inc index)) [(assoc cell prop-span 1) - (assoc cell :id (uuid/next) :shapes [] prop (inc (get cell prop)) prop-span (dec (get cell prop-span)))] + (-> cell + (assoc :id (uuid/next) :shapes [] prop (inc (get cell prop)) prop-span (dec (get cell prop-span))) + (dissoc :area-name) + (cond-> area? (assoc :position :manual)))] ;; New track at the middle (< (get cell prop) (inc index) (+ (get cell prop) (dec (get cell prop-span)))) [(assoc cell prop-span (- (inc index) (get cell prop))) - (assoc cell :id (uuid/next) :shapes [] prop (inc index) prop-span 1) - (assoc cell :id (uuid/next) :shapes [] prop (+ index 2) prop-span (- (+ (get cell prop) (dec (get cell prop-span))) (inc index)))] + (-> cell + (assoc :id (uuid/next) :shapes [] prop (inc index) prop-span 1) + (dissoc :area-name) + (cond-> area? (assoc :position :manual))) + (-> cell + (assoc :id (uuid/next) :shapes [] prop (+ index 2) prop-span (- (+ (get cell prop) (dec (get cell prop-span))) (inc index))) + (dissoc :area-name) + (cond-> area? (assoc :position :manual)))] ;; New track at the end (= (+ (get cell prop) (dec (get cell prop-span))) (inc index)) [(assoc cell prop-span (- (inc index) (get cell prop))) - (assoc cell :id (uuid/next) :shapes [] prop (inc index) prop-span 1)])] + (-> cell + (assoc :id (uuid/next) :shapes [] prop (inc index) prop-span 1) + (dissoc :area-name) + (cond-> area? (assoc :position :manual)))])] (->> changed-cells (reduce #(update %1 :layout-grid-cells assoc (:id %2) %2) parent)))) @@ -659,17 +672,24 @@ (filter #(> (get % prop-span) 1)) (reduce (fn [parent cell] - (let [changed-cells + (let [area? (= :area (:position cell)) + changed-cells (cond ;; New track at the beginning (= (get cell prop) (inc index)) [(assoc cell prop-span 1) - (assoc cell :id (uuid/next) :shapes [] prop (inc (get cell prop)) prop-span (dec (get cell prop-span)))] + (-> cell + (assoc :id (uuid/next) :shapes [] prop (inc (get cell prop)) prop-span (dec (get cell prop-span))) + (dissoc :area-name) + (cond-> area? (assoc :position :manual)))] ;; New track at the middle (< (get cell prop) (inc index) (+ (get cell prop) (dec (get cell prop-span)))) [(assoc cell prop-span (- (+ index 2) (get cell prop))) - (assoc cell :id (uuid/next) :shapes [] prop (+ index 2) prop-span (- (+ (get cell prop) (dec (get cell prop-span))) (inc index)))])] + (-> cell + (assoc :id (uuid/next) :shapes [] prop (+ index 2) prop-span (- (+ (get cell prop) (dec (get cell prop-span))) (inc index))) + (dissoc :area-name) + (cond-> area? (assoc :position :manual)))])] (->> changed-cells (reduce #(update %1 :layout-grid-cells assoc (:id %2) %2) parent)))) parent)))) @@ -776,6 +796,8 @@ (let [match-cell (-> (get to-cells-idx (get cell prop-other)) (d/patch-object (select-keys cell [prop-other-span :position :align-self :justify-self])) + (cond-> (= :area (:position cell)) + (assoc :position :manual)) (cond-> (= (get cell prop-span) 1) (assoc :shapes (mapv ids-map (:shapes cell)))))] (recur (rest from-cells) @@ -796,20 +818,22 @@ (defn duplicate-row - [shape index ids-map] + [shape objects index ids-map] (let [value (dm/get-in shape [:layout-grid-rows index])] (-> shape (remove-cell-areas-after :row index) (add-grid-row value (inc index)) - (duplicate-cells :row index (inc index) ids-map)))) + (duplicate-cells :row index (inc index) ids-map) + (assign-cells objects)))) (defn duplicate-column - [shape index ids-map] + [shape objects index ids-map] (let [value (dm/get-in shape [:layout-grid-columns index])] (-> shape (remove-cell-areas-after :column index) (add-grid-column value (inc index)) - (duplicate-cells :column index (inc index) ids-map)))) + (duplicate-cells :column index (inc index) ids-map) + (assign-cells objects)))) (defn make-remove-cell [attr span-attr track-num] @@ -1024,6 +1048,41 @@ parent overlaps)) +(defn reassign-positions + "Propagate the manual positioning to the following cells" + [parent] + (->> (cells-seq parent :sort? true) + (reduce + (fn [[parent auto?] cell] + + (let [[cell auto?] + (cond + (and (empty? (:shapes cell)) + (= :manual (:position cell)) + (= (:row-span cell) 1) + (= (:column-span cell) 1)) + [(assoc cell :position :auto) false] + + (and (or (not= (:row-span cell) 1) + (not= (:column-span cell) 1)) + (= :auto (:position cell))) + [(assoc cell :position :manual) false] + + (empty? (:shapes cell)) + [cell false] + + (and (not auto?) (= :auto (:position cell))) + [(assoc cell :position :manual) false] + + (= :manual (:position cell)) + [cell false] + + :else + [cell auto?])] + [(assoc-in parent [:layout-grid-cells (:id cell)] cell) auto?])) + [parent true]) + (first))) + (defn position-auto-shapes [parent] ;; Iterate through the cells. While auto and contains shape no changes. @@ -1050,6 +1109,14 @@ (rest shapes)))))] parent)) +(defn assign-cell-positions + [parent objects] + (prn ">>>>assign-cell-positions" (:name parent)) + (-> parent + (check-deassigned-cells objects) + (reassign-positions) + (position-auto-shapes))) + ;; Assign cells takes the children and move them into the allotted cells. If there are not enough cells it creates ;; not-tracked rows/columns and put the shapes there ;; Non-tracked tracks need to be deleted when they are empty and there are no more shapes unallocated @@ -1061,13 +1128,10 @@ ;; - (maybe) create group/frames. This case will assigna a cell that had one of its children (defn assign-cells [parent objects] - (let [;; TODO: Remove this, shouldn't be happening - ;;overlaps (overlapping-cells parent) - ;;_ (when (not (empty? overlaps)) - ;; (.warn js/console "OVERLAPS" overlaps)) - parent (cond-> (check-deassigned-cells parent objects) - #_(d/not-empty? overlaps) - #_(fix-overlaps overlaps)) + (prn ">assign-cells") + (let [ + + parent (assign-cell-positions parent objects) shape-has-cell? (into #{} (mapcat (comp :shapes second)) (:layout-grid-cells parent)) @@ -1075,9 +1139,7 @@ no-cell-shapes (->> (:shapes parent) (remove shape-has-cell?) - (remove (partial position-absolute? objects))) - - parent (position-auto-shapes parent)] + (remove (partial position-absolute? objects)))] (if (empty? no-cell-shapes) ;; All shapes are within a cell. No need to assign @@ -1415,13 +1477,16 @@ (<= first-column (+ column column-span -1) last-column))))))) (defn shapes-by-row + "Find all the shapes for a given row" ([parent index] (shapes-by-row parent index true)) + ;; check-span? if false will only see if there is a coincidence in file&row ([parent index check-span?] (->> (cells-by-row parent index check-span?) (mapcat :shapes)))) (defn shapes-by-column + "Find all the shapes for a given column" ([parent index] (shapes-by-column parent index true)) ([parent index check-span?] @@ -1487,7 +1552,7 @@ [r c])))) (defn remap-grid-cells - "Remaps the shapes inside the cells" + "Remaps the shapes ids inside the cells" [shape ids-map] (let [do-remap-cells (fn [cell] diff --git a/frontend/src/app/main/data/workspace/changes.cljs b/frontend/src/app/main/data/workspace/changes.cljs index 7a5b55062d..061b3c5503 100644 --- a/frontend/src/app/main/data/workspace/changes.cljs +++ b/frontend/src/app/main/data/workspace/changes.cljs @@ -15,6 +15,7 @@ [app.common.logging :as log] [app.common.schema :as sm] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] @@ -87,6 +88,8 @@ (cond-> undo-group (pcb/set-undo-group undo-group))) ids) + grid-ids (->> ids (filter (partial ctl/grid-layout? objects))) + changes (pcb/update-shapes changes grid-ids ctl/assign-cell-positions {:with-objects? true}) changes (pcb/reorder-grid-children changes ids) changes (add-undo-group changes state)] (rx/concat diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 4566ad26af..b6828a1941 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -500,7 +500,6 @@ (pcb/amend-last-change #(assoc % :old-id (:id obj))) (cond-> (ctl/grid-layout? objects (:parent-id obj)) (-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells {:with-objects? true}) - (pcb/update-shapes [(:parent-id obj)] ctl/check-deassigned-cells {:with-objects? true}) (pcb/reorder-grid-children [(:parent-id obj)])))) changes (cond-> changes diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 2f8c397fa6..cc29ceca61 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -342,12 +342,13 @@ (-> changes (pcb/update-shapes ids - (fn [shape] + (fn [shape objects] ;; The duplication could have altered the grid so we restore the values, we'll calculate the good ones now (let [shape (merge shape (select-keys base-shape [:layout-grid-cells :layout-grid-columns :layout-grid-rows]))] (case type - :row (ctl/duplicate-row shape index ids-map) - :column (ctl/duplicate-column shape index ids-map)))))) + :row (ctl/duplicate-row shape objects index ids-map) + :column (ctl/duplicate-column shape objects index ids-map)))) + {:with-objects? true})) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 74d0e31f28..16904a1eee 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -559,8 +559,8 @@ (fn [[_ target-frame drop-index]] (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwm/apply-modifiers {:undo-transation? false}) (move-shapes-to-frame ids target-frame drop-index) + (dwm/apply-modifiers {:undo-transation? false}) (finish-transform) (dwu/commit-undo-transaction undo-id)))))))))))))) @@ -872,7 +872,9 @@ (pcb/update-shapes moving-shapes-ids #(cond-> % (cfh/frame-shape? %) (assoc :hide-in-viewer true))) (pcb/update-shapes shape-ids-to-detach ctk/detach-shape) (pcb/change-parent frame-id moving-shapes drop-index) - (pcb/reorder-grid-children [frame-id]) + (cond-> (ctl/grid-layout? objects frame-id) + (-> (pcb/update-shapes [frame-id] ctl/assign-cell-positions {:with-objects? true}) + (pcb/reorder-grid-children [frame-id]))) (pcb/remove-objects empty-parents))] (when (and (some? frame-id) (d/not-empty? changes)) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 3d9106d8ab..fcac73c07b 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -30,6 +30,7 @@ [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] [app.main.ui.workspace.viewport.viewport-ref :as uwvv] + [app.util.debug :as dbg] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] @@ -347,6 +348,29 @@ (st/emit! (dw/show-grid-cell-context-menu {:position position :grid-id (:id shape)})))))] [:g.cell-editor + ;; DEBUG OVERLAY + (when (dbg/enabled? :grid-cells) + [:g.debug-cell {:pointer-events "none" + :transform (dm/str (gmt/transform-in cell-center (:transform shape)))} + + [:rect + {:x (:x cell-origin) + :y (:y cell-origin) + :width cell-width + :height cell-height + :fill (cond + (= (:position cell) :auto) "green" + (= (:position cell) :manual) "red" + (= (:position cell) :area) "yellow" + :else "black") + :fill-opacity 0.2}] + + (when (seq (:shapes cell)) + [:circle + {:cx (+ (:x cell-origin) cell-width (- (/ 7 zoom))) + :cy (+ (:y cell-origin) (/ 7 zoom)) + :r (/ 5 zoom) + :fill "red"}])]) [:rect {:transform (dm/str (gmt/transform-in cell-center (:transform shape))) :class (dom/classnames (stl/css :grid-cell-outline) true diff --git a/frontend/src/app/util/debug.cljs b/frontend/src/app/util/debug.cljs index 7fecae2192..7bf6304bde 100644 --- a/frontend/src/app/util/debug.cljs +++ b/frontend/src/app/util/debug.cljs @@ -75,6 +75,9 @@ ;; :grid-layout + + ;; Show an overlay to the grid cells to know its properties + :grid-cells }) (defn enable! diff --git a/frontend/translations/en.po b/frontend/translations/en.po index b01c7a11c4..1d1addfc4a 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5080,7 +5080,7 @@ msgid "workspace.context-menu.grid-track.row.add-before" msgstr "Add 1 row above" msgid "workspace.context-menu.grid-track.row.add-after" -msgstr "Add 1 row bellow" +msgstr "Add 1 row below" msgid "workspace.context-menu.grid-track.row.delete" msgstr "Delete row" From 4899b3af6ea39f9b54717f96eee9bb61d0ccb9fe Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 4 Jan 2024 16:27:08 +0100 Subject: [PATCH 35/35] :bug: Fix incorrect pointer deref on validating file on update operation --- backend/src/app/rpc/commands/files_update.clj | 2 +- backend/src/app/srepl/helpers.clj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/app/rpc/commands/files_update.clj b/backend/src/app/rpc/commands/files_update.clj index 96b92c0d6e..03e1b04da4 100644 --- a/backend/src/app/rpc/commands/files_update.clj +++ b/backend/src/app/rpc/commands/files_update.clj @@ -306,7 +306,7 @@ (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id) pmap/*tracked* nil] (-> (files/get-file cfg id :migrate? false) - (feat.fdata/process-pointers deref) ; ensure all pointers resolved + (update :data feat.fdata/process-pointers deref) ; ensure all pointers resolved (fmg/migrate-file)))))) (d/index-by :id))) diff --git a/backend/src/app/srepl/helpers.clj b/backend/src/app/srepl/helpers.clj index bc8caf6c17..c135d3e763 100644 --- a/backend/src/app/srepl/helpers.clj +++ b/backend/src/app/srepl/helpers.clj @@ -83,7 +83,7 @@ (into [file] (map (fn [{:keys [id]}] (binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)] (-> (files/get-file system id :migrate? false) - (feat.fdata/process-pointers deref) + (update :data feat.fdata/process-pointers deref) (pmg/migrate-file)))))) (d/index-by :id))] (validate/validate-file file libs)))))) @@ -101,7 +101,7 @@ (into [file] (map (fn [{:keys [id]}] (binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)] (-> (files/get-file system id :migrate? false) - (feat.fdata/process-pointers deref) + (update :data feat.fdata/process-pointers deref) (pmg/migrate-file)))))) (d/index-by :id)) errors (validate/validate-file file libs)