From af7142e97b76ea46b08200df35d1beeef784c201 Mon Sep 17 00:00:00 2001 From: "alonso.torres" <alonso.torres@kaleidos.net> Date: Mon, 12 Feb 2024 11:49:34 +0100 Subject: [PATCH 01/23] :sparkles: New overlay for v2 information --- backend/src/app/rpc/commands/auth.clj | 3 +- frontend/resources/images/icons/v2-icon-1.svg | 1 + frontend/resources/images/icons/v2-icon-2.svg | 1 + frontend/resources/images/icons/v2-icon-3.svg | 1 + frontend/resources/images/icons/v2-icon-4.svg | 1 + .../styles/common/refactor/fonts.scss | 1 + frontend/src/app/main/data/workspace.cljs | 13 ++-- .../app/main/ui/dashboard/change_owner.scss | 4 ++ frontend/src/app/main/ui/icons.cljs | 5 ++ .../src/app/main/ui/workspace/libraries.cljs | 56 ++++++++++++++++ .../src/app/main/ui/workspace/libraries.scss | 67 +++++++++++++++++++ 11 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 frontend/resources/images/icons/v2-icon-1.svg create mode 100644 frontend/resources/images/icons/v2-icon-2.svg create mode 100644 frontend/resources/images/icons/v2-icon-3.svg create mode 100644 frontend/resources/images/icons/v2-icon-4.svg diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index 66bec377d..8e9671e59 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -262,7 +262,8 @@ (merge (:props params)) (merge {:viewed-tutorial? false :viewed-walkthrough? false - :nudge {:big 10 :small 1}}) + :nudge {:big 10 :small 1} + :v2-info-shown true}) (db/tjson)) password (or (:password params) "!") diff --git a/frontend/resources/images/icons/v2-icon-1.svg b/frontend/resources/images/icons/v2-icon-1.svg new file mode 100644 index 000000000..b39647eb1 --- /dev/null +++ b/frontend/resources/images/icons/v2-icon-1.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="4494 307 310 290"><path d="m4643.25 309.15-18.86 15.75a9.32 9.32 0 0 0-1.2 13.1 9.26 9.26 0 0 0 13.07 1.2l3.67-3.05.2 82.04a103.8 103.8 0 0 0-14.46-19.07c-15.68-16.23-36.46-25.7-59.17-26.11a86.83 86.83 0 0 0-11.04.52l1.91-3.29a9.32 9.32 0 0 0-3.42-12.57 9.26 9.26 0 0 0-12.6 3.2l-12.59 21.63a9.32 9.32 0 0 0 2.1 11.86l18.93 15.67a9.26 9.26 0 0 0 9.16 1.54 9.32 9.32 0 0 0 2.66-15.9l-4.42-3.66c21.64-2.66 40.4 4.82 55.14 20.07 16.68 17.27 27.77 45.12 27.98 79.86-.05 9.54.04 19.06.07 28.6-10.61-16.53-24.8-30.38-40.13-40.85-15.92-10.87-33.13-18.28-49.55-21.38-8.2-1.55-16.3-2.04-23.93-1.2-2.3.26-4.6.66-6.85 1.2l1.09-2.8a9.27 9.27 0 0 0-17.27-6.77l-9.1 23.32a9.32 9.32 0 0 0 3.91 11.4l21.13 12.53a9.26 9.26 0 0 0 12.54-3.37 9.32 9.32 0 0 0-3.1-12.65l-5.56-3.3c6.54-1.62 14.64-1.77 23.72-.05 13.42 2.53 28.56 8.92 42.53 18.46 27.92 19.09 50.72 50.2 50.72 87.3v.03l.02 5.3a9.3 9.3 0 0 0 9.3 9.29 9.29 9.29 0 0 0 9.25-9.32v-2.77c.5-37.1 19.92-67.3 48.22-89.72 13.17-9.62 27.44-15.99 39.99-18.46 10.08-2 18.76-1.4 25.26 1.19l-4 2.43a9.32 9.32 0 0 0-3.14 12.79 9.26 9.26 0 0 0 12.74 3.14l21.37-13a9.32 9.32 0 0 0 3.78-11.43l-9.17-22.82a9.27 9.27 0 1 0-17.21 6.96l1.72 4.29a50.78 50.78 0 0 0-11.87-2.93c-7.38-.92-15.18-.45-23.06 1.11-15.78 3.1-32.2 10.63-47.34 21.68a142.37 142.37 0 0 0-37.45 40.54l-.07-24.5c.65-34.78 11.26-64.22 26.98-82.93 15.4-18.33 34.64-26.71 56.88-22.07l-4.52 2.74a9.32 9.32 0 0 0-3 12.7 9.26 9.26 0 0 0 12.6 3.22l21.37-12.99a9.32 9.32 0 0 0 3.79-11.43l-9.17-22.83a9.27 9.27 0 0 0-12.08-5.15 9.32 9.32 0 0 0-5.14 12.11l1.5 3.74a73.41 73.41 0 0 0-19.47-1.8c-22.03.99-42.11 12.09-56.95 29.76a115.7 115.7 0 0 0-12.97 19.25l-.2-83.78 3.47 3.03a9.26 9.26 0 0 0 12.97-1.03 9.32 9.32 0 0 0-.8-13.02l-18.87-16.42a9.26 9.26 0 0 0-12.01-.13Z" paint-order="fill markers"/></svg> diff --git a/frontend/resources/images/icons/v2-icon-2.svg b/frontend/resources/images/icons/v2-icon-2.svg new file mode 100644 index 000000000..d384ee2ed --- /dev/null +++ b/frontend/resources/images/icons/v2-icon-2.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="4870 326 249.25 261.8"><path fill="#000" d="M5050.75 326.04a8.57 8.57 0 0 0-7.77 3.58l-19.12 27.03a8.57 8.57 0 0 0 0 9.9l19.12 27.04a8.57 8.57 0 0 0 15.44-3.5 8.57 8.57 0 0 0-1.45-6.4l-8.43-11.92c13.34-.5 22.4 1.84 28.61 5.26 6.78 3.74 10.6 8.83 13.14 14.83 2.54 6 3.51 12.91 3.77 19.07.24 6.16-.26 11.02-.19 15.04a8.57 8.57 0 0 0 8.7 8.43 8.57 8.57 0 0 0 8.44-8.69c-.02-1.7.47-8.1.17-15.49-.3-7.37-1.4-16.26-5.1-25.03a46.95 46.95 0 0 0-20.64-23.17c-9.83-5.43-22.72-8.14-39.22-7.3l10.75-15.21a8.57 8.57 0 0 0-2.05-11.93 8.56 8.56 0 0 0-4.17-1.54Zm-158.97 1.7A21.92 21.92 0 0 0 4870 349.5v61.37a21.92 21.92 0 0 0 21.77 21.78h61.38a21.92 21.92 0 0 0 21.78-21.77v-61.37a21.92 21.92 0 0 0-21.77-21.79h-61.38Zm0 17.13h61.37a4.46 4.46 0 0 1 4.64 4.64v61.37a4.46 4.46 0 0 1-4.63 4.65h-61.38a4.45 4.45 0 0 1-4.63-4.65v-61.37a4.45 4.45 0 0 1 4.63-4.63Zm-5.1 134.52a8.57 8.57 0 0 0-8.43 8.7c.02 1.7-.47 8.1-.17 15.47.3 7.37 1.4 16.26 5.1 25.04a47 47 0 0 0 20.65 23.18c9.83 5.41 22.7 8.14 39.2 7.3l-10.74 15.2a8.57 8.57 0 0 0 8.44 13.4 8.57 8.57 0 0 0 5.56-3.51l19.1-27.04a8.57 8.57 0 0 0 0-9.9l-19.1-27.03a8.57 8.57 0 0 0-5.56-3.5 8.57 8.57 0 0 0-8.44 13.4l8.42 11.92c-13.34.5-22.4-1.82-28.6-5.24-6.78-3.74-10.6-8.83-13.14-14.83-2.54-6.02-3.51-12.92-3.77-19.08-.24-6.16.26-11.02.2-15.03a8.57 8.57 0 0 0-8.71-8.45Zm152.1 1.74a24.6 24.6 0 0 0-24.46 24.46v56.02a24.6 24.6 0 0 0 24.47 24.45h56a24.6 24.6 0 0 0 24.46-24.45v-56.02a24.6 24.6 0 0 0-24.45-24.46h-56.02Zm0 17.14h56.02a7.12 7.12 0 0 1 7.31 7.32v56.02a7.11 7.11 0 0 1-7.31 7.3h-56.02a7.12 7.12 0 0 1-5.23-2.07 7.12 7.12 0 0 1-2.09-5.23v-56.02a7.11 7.11 0 0 1 7.33-7.32Z" class="fills" color="#000" paint-order="fill markers"/></svg> diff --git a/frontend/resources/images/icons/v2-icon-3.svg b/frontend/resources/images/icons/v2-icon-3.svg new file mode 100644 index 000000000..bfc88da6d --- /dev/null +++ b/frontend/resources/images/icons/v2-icon-3.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="4563 696 212.14 362.63"><path d="M4669.07 696a41.22 41.22 0 0 0-29.24 12.07l-64.76 64.75a41.47 41.47 0 0 0 0 58.49l8.39 8.39-8.39 8.38a41.47 41.47 0 0 0 0 58.5l8.38 8.38-8.36 8.37a41.47 41.47 0 0 0 0 58.49l64.73 64.73a41.48 41.48 0 0 0 58.5.01l64.74-64.73a41.49 41.49 0 0 0 0-58.51l-8.37-8.38 8.37-8.37a41.47 41.47 0 0 0 0-58.5l-8.38-8.37 8.39-8.38a41.47 41.47 0 0 0 0-58.5l-64.75-64.75a41.25 41.25 0 0 0-29.25-12.07Zm0 18.28a22.85 22.85 0 0 1 16.2 6.83l64.76 64.75a22.68 22.68 0 0 1 0 32.42l-64.74 64.75a22.68 22.68 0 0 1-32.43.01l-64.76-64.75a22.68 22.68 0 0 1 0-32.43l64.75-64.75a22.86 22.86 0 0 1 16.22-6.83Zm0 52.73c-4.3 0-8.62 1.62-11.85 4.85l-18.35 18.36a16.89 16.89 0 0 0 0 23.7l18.35 18.35a16.89 16.89 0 0 0 23.7 0l18.36-18.35a16.89 16.89 0 0 0-.01-23.7l-18.35-18.35a16.7 16.7 0 0 0-11.85-4.86Zm0 15.19c.34 0 .68.16 1.01.5l18.36 18.35c.66.67.68 1.38.01 2.05l-18.35 18.35c-.67.67-1.4.67-2.06 0l-18.36-18.35c-.66-.66-.65-1.39.01-2.05l18.35-18.35c.34-.33.68-.5 1.03-.5Zm-72.58 70.53 43.33 43.33a41.47 41.47 0 0 0 58.5.01l43.33-43.33 8.37 8.37a22.68 22.68 0 0 1 0 32.42l-64.75 64.75a22.68 22.68 0 0 1-32.43 0l-64.73-64.73a22.68 22.68 0 0 1 0-32.44Zm145.17 75.24 8.37 8.37a22.7 22.7 0 0 1 0 32.45l-64.74 64.74a22.7 22.7 0 0 1-32.44-.01l-64.73-64.74a22.67 22.67 0 0 1 0-32.42l8.36-8.37 43.33 43.33a41.47 41.47 0 0 0 58.5 0Z" paint-order="fill markers"/></svg> diff --git a/frontend/resources/images/icons/v2-icon-4.svg b/frontend/resources/images/icons/v2-icon-4.svg new file mode 100644 index 000000000..dc2443432 --- /dev/null +++ b/frontend/resources/images/icons/v2-icon-4.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="4870 696 216.34 319.12"><path d="M5052.72 696a5.69 5.69 0 0 0-5.8 4.77c-1.72 10.62-4.08 20.19-7.8 27-3.71 6.79-8.19 10.82-15.77 12.25-6.11 1.16-6.17 9.92-.07 11.15 7.97 1.64 12.63 5.72 16.33 12.39 3.7 6.68 5.93 16.05 7.27 26.7.89 6.88 10.98 6.47 11.32-.46.83-18.37 4.47-27.31 8.37-31.76 3.9-4.45 8.67-5.56 15.17-6.85 5.8-1.12 6.24-9.26.6-11.01-7.53-2.35-12.77-6.54-16.73-12.94-3.95-6.4-6.46-15.15-7.41-26.06a5.69 5.69 0 0 0-5.48-5.18Zm-151.65 71.03c-17.13.1-31 13.97-31.07 31.1v185.9a31.21 31.21 0 0 0 31.07 31.09h136.32a31.24 31.24 0 0 0 31.1-31.08V871.7c0-6.01-1.92-12.93-6.51-17.91-21.13-22.9-59.2-64.23-73.79-78.82-4-4.01-10.62-7.95-17.97-7.95Zm0 18.43h65.88v71.29c0 6.42 4.03 12.41 8.53 15.12 4.51 2.71 9.05 3.33 13.15 3.33h61.43v108.83a12.44 12.44 0 0 1-12.67 12.66h-136.32a12.42 12.42 0 0 1-12.65-12.66v-185.9a12.44 12.44 0 0 1 12.65-12.67Zm84.31 13.15a5423.07 5423.07 0 0 1 54.24 58.17h-50.99a8.99 8.99 0 0 1-3.25-.62Z" paint-order="fill markers"/></svg> diff --git a/frontend/resources/styles/common/refactor/fonts.scss b/frontend/resources/styles/common/refactor/fonts.scss index 40d1dcb87..c4bc4cb3f 100644 --- a/frontend/resources/styles/common/refactor/fonts.scss +++ b/frontend/resources/styles/common/refactor/fonts.scss @@ -15,6 +15,7 @@ $fs-11: 0.688rem; $fs-12: math.div(12, $fs-base) + rem; $fs-14: math.div(14, $fs-base) + rem; $fs-16: math.div(16, $fs-base) + rem; +$fs-18: math.div(18, $fs-base) + rem; $fs-24: math.div(24, $fs-base) + rem; $fs-36: math.div(36, $fs-base) + rem; diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 46d847794..0249bf2ca 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -35,6 +35,7 @@ [app.main.data.events :as ev] [app.main.data.fonts :as df] [app.main.data.messages :as msg] + [app.main.data.modal :as modal] [app.main.data.users :as du] [app.main.data.workspace.bool :as dwb] [app.main.data.workspace.changes :as dch] @@ -119,10 +120,14 @@ (assoc :workspace-ready? true))) ptk/WatchEvent - (watch [_ _ _] - (rx/of (fbc/fix-bool-contents) - (fdf/fix-deleted-fonts) - (fbs/fix-broken-shapes))))) + (watch [_ state _] + (rx/of + (when (and (not (boolean (-> state :profile :props :v2-info-shown))) + (features/active-feature? state "components/v2")) + (modal/show :v2-info {})) + (fbc/fix-bool-contents) + (fdf/fix-deleted-fonts) + (fbs/fix-broken-shapes))))) (defn- workspace-data-loaded [data] diff --git a/frontend/src/app/main/ui/dashboard/change_owner.scss b/frontend/src/app/main/ui/dashboard/change_owner.scss index 2da4ec233..c1f6bf7d9 100644 --- a/frontend/src/app/main/ui/dashboard/change_owner.scss +++ b/frontend/src/app/main/ui/dashboard/change_owner.scss @@ -50,3 +50,7 @@ @extend .modal-danger-btn; } } + +.modal-msg { + color: var(--modal-text-foreground-color); +} diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index e90cc022e..f65ff1676 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -479,6 +479,11 @@ (def ^:icon cap-round (icon-xref :cap-round)) (def ^:icon cap-square (icon-xref :cap-square)) +(def ^:icon v2-icon-1 (icon-xref :v2-icon-1)) +(def ^:icon v2-icon-2 (icon-xref :v2-icon-2)) +(def ^:icon v2-icon-3 (icon-xref :v2-icon-3)) +(def ^:icon v2-icon-4 (icon-xref :v2-icon-4)) + (def ^:icon loader-pencil (mf/html diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 3262f202b..871c53799 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -15,6 +15,7 @@ [app.common.types.typographies-list :as ctyl] [app.common.uuid :as uuid] [app.main.data.modal :as modal] + [app.main.data.users :as du] [app.main.data.workspace.libraries :as dwl] [app.main.refs :as refs] [app.main.render :refer [component-svg]] @@ -511,3 +512,58 @@ [:& updates-tab {:file-id file-id :file-data file-data :libraries libraries}]]]]]]]])) + +(mf/defc v2-info-dialog + {::mf/register modal/components + ::mf/register-as :v2-info} + [] + (let [handle-gotit-click + (mf/use-fn + (fn [] + (modal/hide!) + (st/emit! (du/update-profile-props {:v2-info-shown true}))))] + + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-dialog :modal-v2-info)} + [:div {:class (stl/css :modal-title)} "IMPORTANT INFORMATION ABOUT NEW COMPONENTS"] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :info-content)} + [:div {:class (stl/css :info-block)} + [:div {:class (stl/css :info-icon)} i/v2-icon-1] + [:div {:class (stl/css :info-block-title)} + "One physical source of truth"] + [:div {:class (stl/css :info-block-content)} + "Main components are now found at the design space. They act as a single source " + "of truth and can be worked on with their copies. This ensures consistency and " + "allows better control and synchronization."]] + + [:div {:class (stl/css :info-block)} + [:div {:class (stl/css :info-icon)} i/v2-icon-2] + [:div {:class (stl/css :info-block-title)} + "Swap components"] + [:div {:class (stl/css :info-block-content)} + "Now, you can replace one component copy with another within your libraries. " + "The swap components functionality streamlines making changes, testing " + "variations, or updating elements without extensive manual adjustments."]] + + [:div {:class (stl/css :info-block)} + [:div {:class (stl/css :info-icon)} i/v2-icon-3] + [:div {:class (stl/css :info-block-title)} + "Graphic assets no longer exist"] + [:div {:class (stl/css :info-block-content)} + "Graphic assets now disappear, so that all graphic assets become components. " + "This way, swapping between them is possible, and we avoid confusion about " + "what should go in each typology."]] + + [:div {:class (stl/css :info-block)} + [:div {:class (stl/css :info-icon)} i/v2-icon-4] + [:div {:class (stl/css :info-block-title)} + "Main components page"] + [:div {:class (stl/css :info-block-content)} + "You might find that a new page called 'Main components' has appeared in " + "your file. On that page, you'll find all the main components that were " + "created in your files previously to this new version."]]] + + [:div {:class (stl/css :info-bottom)} + [:button {:class (stl/css :primary-button) + :on-click handle-gotit-click} "I GOT IT"]]]]])) diff --git a/frontend/src/app/main/ui/workspace/libraries.scss b/frontend/src/app/main/ui/workspace/libraries.scss index 2664f3209..3fa999a1e 100644 --- a/frontend/src/app/main/ui/workspace/libraries.scss +++ b/frontend/src/app/main/ui/workspace/libraries.scss @@ -228,6 +228,15 @@ } } } + + .modal-v2-info { + width: $s-664; + height: fit-content; + + .modal-title { + font-size: $fs-18; + } + } } .item-contents { @@ -245,3 +254,61 @@ margin-inline: $s-4; } } + +.info-content { + margin-top: $s-32; + display: flex; + flex-direction: column; + gap: $s-24; + + .info-block { + display: grid; + grid-template-columns: auto 1fr; + column-gap: $s-20; + grid-template: + "icon title" + "icon content"; + } + + .info-icon { + grid-area: icon; + width: $s-52; + height: $s-52; + margin-top: $s-8; + border-radius: $br-circle; + background: $db-quaternary; + + display: flex; + justify-content: center; + align-items: center; + + svg { + width: $s-32; + height: $s-32; + fill: $da-primary; + } + } + .info-block-title { + grid-area: title; + font-size: $fs-16; + color: $df-primary; + } + .info-block-content { + grid-area: content; + font-size: $fs-14; + color: $df-secondary; + line-height: 1.2; + } +} + +.info-bottom { + margin-top: $s-24; + margin-right: $s-8; + display: flex; + justify-content: flex-end; + .primary-button { + @extend .button-primary; + @include tabTitleTipography; + padding: $s-0 $s-16; + } +} From 39b5f10529a0577ac5c5dd85eed983f3c0748bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= <andres.moya@kaleidos.net> Date: Mon, 12 Feb 2024 17:40:13 +0100 Subject: [PATCH 02/23] :bug: Fix update main when there are swapped copies --- common/src/app/common/types/container.cljc | 7 -- common/src/app/common/types/file.cljc | 21 +++++- .../app/main/data/workspace/libraries.cljs | 6 +- .../data/workspace/libraries_helpers.cljs | 74 ++++++++++++------- 4 files changed, 68 insertions(+), 40 deletions(-) diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index c217969e1..4265329ea 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -166,13 +166,6 @@ :else (get-instance-root objects (get objects (:parent-id shape))))) -(defn get-copy-root - "Get the top shape of the copy." - [objects shape] - (when (:shape-ref shape) - (let [parent (cfh/get-parent objects (:id shape))] - (or (get-copy-root objects parent) shape)))) - (defn inside-component-main? "Check if the shape is a component main instance or is inside one." [objects shape] diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index 3f8e7b3bd..1fd8b1f00 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -190,7 +190,7 @@ "Locate the near component in the local file or libraries, and retrieve the shape referenced by the instance shape." [file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}] - (let [root-shape (ctn/get-copy-root (:objects page) shape) + (let [root-shape (ctn/get-component-shape (:objects page) shape) component-file (when root-shape (if (and (some? file) (= (:component-file root-shape) (:id file))) file @@ -218,10 +218,23 @@ component-file (get-in libraries [(:component-file top-instance) :data]) component (ctkl/get-component component-file (:component-id top-instance) true) remote-shape (get-ref-shape component-file component shape) - component-container (get-component-container component-file component)] + component-container (get-component-container component-file component) + [remote-shape component-container] + (if (some? remote-shape) + [remote-shape component-container] + ;; If not found, try the case of this being a fostered or swapped children + (let [head-instance (ctn/get-head-shape (:objects container) shape) + component-file (get-in libraries [(:component-file head-instance) :data]) + head-component (ctkl/get-component component-file (:component-id head-instance) true) + remote-shape' (get-ref-shape component-file head-component shape) + component-container (get-component-container component-file component)] + [remote-shape' component-container]))] + (if (nil? remote-shape) - shape - (find-remote-shape component-container libraries remote-shape)))) + nil + (if (nil? (:shape-ref remote-shape)) + remote-shape + (find-remote-shape component-container libraries remote-shape))))) (defn get-component-shapes "Retrieve all shapes of the component" diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 269701c78..1fab0ddcd 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -77,7 +77,11 @@ extract (cond-> {:type (:type change) :raw-change change} shape - (assoc :shape (str prefix (:name shape))) + (assoc :shape (str prefix (:name shape)) + :shape-id (str (:id shape))) + (:obj change) + (assoc :obj (:name (:obj change)) + :obj-id (:id (:obj change))) (:operations change) (assoc :operations (:operations change)))] extract))] diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index d19e776f3..9f19e14e6 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -886,7 +886,6 @@ (map #(redirect-shaperef %) children-inst) children-inst) - only-inst (fn [changes child-inst] (add-shape-to-main changes child-inst @@ -1088,10 +1087,8 @@ root-main)) update-original-shape (fn [original-shape new-shape] - (if-not (:shape-ref original-shape) - (assoc original-shape - :shape-ref (:id new-shape)) - original-shape)) + (assoc original-shape + :shape-ref (:id new-shape))) [_new-shape new-shapes updated-shapes] (ctst/clone-shape shape @@ -1116,25 +1113,46 @@ :obj shape'})))) mod-obj-change (fn [changes shape'] - (update changes :redo-changes conj - {:type :mod-obj - :page-id (:id page) - :id (:id shape') - :operations [{:type :set - :attr :component-id - :val (:component-id shape')} - {:type :set - :attr :component-file - :val (:component-file shape')} - {:type :set - :attr :component-root - :val (:component-root shape')} - {:type :set - :attr :shape-ref - :val (:shape-ref shape')} - {:type :set - :attr :touched - :val (:touched shape')}]})) + (let [shape-original (ctn/get-shape page (:id shape'))] + (-> changes + (update :redo-changes conj + {:type :mod-obj + :page-id (:id page) + :id (:id shape') + :operations [{:type :set + :attr :component-id + :val (:component-id shape')} + {:type :set + :attr :component-file + :val (:component-file shape')} + {:type :set + :attr :component-root + :val (:component-root shape')} + {:type :set + :attr :shape-ref + :val (:shape-ref shape')} + {:type :set + :attr :touched + :val (:touched shape')}]}) + (update :undo-changes conj + {:type :mod-obj + :page-id (:id page) + :id (:id shape-original) + :operations [{:type :set + :attr :component-id + :val (:component-id shape-original)} + {:type :set + :attr :component-file + :val (:component-file shape-original)} + {:type :set + :attr :component-root + :val (:component-root shape-original)} + {:type :set + :attr :shape-ref + :val (:shape-ref shape-original)} + {:type :set + :attr :touched + :val (:touched shape-original)}]})))) del-obj-change (fn [changes shape'] (update changes :undo-changes conj @@ -1161,7 +1179,8 @@ parents (cfh/get-parent-ids objects (:id shape)) parent (first parents) children (cfh/get-children-ids objects (:id shape)) - ids (into [(:id shape)] children) + ids (-> (into [(:id shape)] children) + (reverse)) ;; Remove from bottom to top add-redo-change (fn [changes id] (update changes :redo-changes conj @@ -1190,12 +1209,11 @@ (update :redo-changes conj (make-change container {:type :reg-objects - :shapes (vec parents)})) - (add-undo-change (:id shape))) + :shapes (vec parents)}))) changes' (reduce add-undo-change changes' - children)] + ids)] (if (and (cfh/touched-group? parent :shapes-group) omit-touched?) changes From d63e5f520e837fb7ce4cf5865094433ca5827034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Mon, 12 Feb 2024 16:11:50 +0100 Subject: [PATCH 03/23] :bug: Fix opacity display when selecting multiple shapes --- .../ui/workspace/sidebar/options/menus/layer.cljs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 bdfec509f..eea27c06c 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 @@ -23,11 +23,11 @@ (defn opacity->string [opacity] - (if (= opacity :multiple) - "" + (if (not= opacity :multiple) (dm/str (-> opacity (d/coalesce 1) - (* 100))))) + (* 100))) + :multiple)) (mf/defc layer-menu {::mf/wrap-props false} @@ -39,7 +39,7 @@ blocked? (:blocked values) current-blend-mode (or (:blend-mode values) :normal) - current-opacity (:opacity values) + current-opacity (opacity->string (:opacity values)) state* (mf/use-state {:selected-blend-mode current-blend-mode @@ -161,8 +161,8 @@ :title (tr "workspace.options.opacity")} [:span {:class (stl/css :icon)} "%"] [:> numeric-input* - {:value (opacity->string current-opacity) - :placeholder (tr "settings.multiple") + {:value current-opacity + :placeholder "--" :on-change handle-opacity-change :min 0 :max 100 From d3bf35869a7087b9db29439411e92c6fc68e34a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Tue, 13 Feb 2024 12:35:59 +0100 Subject: [PATCH 04/23] :bug: Fix font size for modal links --- frontend/src/app/main/ui/export.scss | 2 +- frontend/src/app/main/ui/onboarding.scss | 2 +- frontend/src/app/main/ui/onboarding/newsletter.scss | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/main/ui/export.scss b/frontend/src/app/main/ui/export.scss index 0f687fe61..f528d2eeb 100644 --- a/frontend/src/app/main/ui/export.scss +++ b/frontend/src/app/main/ui/export.scss @@ -103,7 +103,7 @@ color: var(--modal-text-foreground-color); } .modal-link { - @include titleTipography; + @include bodyLargeTypography; text-decoration: none; cursor: pointer; color: var(--modal-link-foreground-color); diff --git a/frontend/src/app/main/ui/onboarding.scss b/frontend/src/app/main/ui/onboarding.scss index 7c2e1b22f..66ecddbe3 100644 --- a/frontend/src/app/main/ui/onboarding.scss +++ b/frontend/src/app/main/ui/onboarding.scss @@ -78,7 +78,7 @@ } .modal-link { - @include titleTipography; + @include bodyLargeTypography; color: var(--modal-link-foreground-color); margin: 0; } diff --git a/frontend/src/app/main/ui/onboarding/newsletter.scss b/frontend/src/app/main/ui/onboarding/newsletter.scss index 350b75499..86f854597 100644 --- a/frontend/src/app/main/ui/onboarding/newsletter.scss +++ b/frontend/src/app/main/ui/onboarding/newsletter.scss @@ -60,7 +60,7 @@ } .modal-link { - @include titleTipography; + @include bodyLargeTypography; color: var(--modal-link-foreground-color); margin: 0; } From 565bf5fbb8ca484085df5747df09bbac910562c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Tue, 13 Feb 2024 11:42:13 +0100 Subject: [PATCH 05/23] :bug: Fix padding of font size selector --- .../sidebar/options/menus/typography.scss | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) 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 c2ab44d9a..bec81db5b 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 @@ -284,19 +284,6 @@ padding: 0; border: $s-1 solid var(--input-border-color); position: relative; - .font-size-select { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - height: 100%; - width: 100%; - margin: 0; - padding: 0; - .numeric-input { - @extend .input-base; - padding-inline-start: $s-8; - } - } .icon { @include flexCenter; @@ -342,6 +329,20 @@ } } +.font-size-select { + @include removeInputStyle; + @include titleTipography; + height: $s-32; + height: 100%; + width: 100%; + margin: 0; + padding: $s-8; + .numeric-input { + @extend .input-base; + padding: 0; + } +} + .font-selector { @include flexCenter; position: absolute; From c336cbe8ab5c42e5a302cc5f09e2b6c66a3b63c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Tue, 13 Feb 2024 12:01:35 +0100 Subject: [PATCH 06/23] :bug: Fix text transform buttons order --- .../ui/workspace/sidebar/options/menus/typography.cljs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 f759c634a..5f945a406 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 @@ -409,14 +409,14 @@ :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"}]]])) + :id "text-transform-capitalize"}] + [:& radio-button {:icon i/text-lowercase-refactor + :type "checkbox" + :value "lowercase" + :id "text-transform-lowercase"}]]])) (mf/defc text-options {::mf/wrap-props false} From 39cb4a081bac91a673af701ba379d98b1bc09ae2 Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Tue, 13 Feb 2024 10:46:09 +0100 Subject: [PATCH 07/23] :bug: Clean legacy features on binfile (v1) importation --- backend/src/app/binfile/v1.clj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/src/app/binfile/v1.clj b/backend/src/app/binfile/v1.clj index 1e3a7b917..207b40ec9 100644 --- a/backend/src/app/binfile/v1.clj +++ b/backend/src/app/binfile/v1.clj @@ -517,6 +517,15 @@ (update :object-id #(str/replace-first % #"^(.*?)/" (str file-id "/"))))) thumbnails)) +(defn- clean-features + [file] + (update file :features (fn [features] + (if (set? features) + (-> features + (cfeat/migrate-legacy-features) + (set/difference cfeat/backend-only-features)) + #{})))) + (defmethod read-section :v1/files [{:keys [::db/conn ::input ::project-id ::bfc/overwrite ::name] :as system}] @@ -527,6 +536,7 @@ file-id (:id file) file-id' (bfc/lookup-index file-id) + file (clean-features file) thumbnails (:thumbnails file)] (when (not= file-id expected-file-id) From e8a1c58c5d7b9e9d2c68cb057be0a176f43db6a7 Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Tue, 13 Feb 2024 11:14:54 +0100 Subject: [PATCH 08/23] :bug: Fix incorrect change detection on srepl helper process-file --- backend/src/app/srepl/helpers.clj | 2 +- backend/src/app/srepl/main.clj | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/src/app/srepl/helpers.clj b/backend/src/app/srepl/helpers.clj index ba98c2968..9df761db0 100644 --- a/backend/src/app/srepl/helpers.clj +++ b/backend/src/app/srepl/helpers.clj @@ -168,7 +168,7 @@ (update-fn file libs opts) (update-fn file opts))] - (when (and (some? file) + (when (and (some? file') (not (identical? file file'))) (when validate? (cfv/validate-file-schema! file')) (let [file' (update file' :revn inc)] diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index 16e9a0905..9851af8a3 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -380,9 +380,6 @@ "Apply a function to all files in the database, reading them in batches. Do not change data. - The `on-file` parameter should be a function that receives the file - and the previous state and returns the new state. - Emits rollback at the end of operation." [on-file & {:keys [max-items start-at with-libraries?]}] (letfn [(get-candidates [conn] From 1cb6f433392b5b8506403da7c9b1b74911deb613 Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Tue, 13 Feb 2024 11:21:02 +0100 Subject: [PATCH 09/23] :paperclip: Add srepl fix function for disable fdata features --- backend/src/app/srepl/fixes.clj | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backend/src/app/srepl/fixes.clj b/backend/src/app/srepl/fixes.clj index 955b87f81..5e450e0d9 100644 --- a/backend/src/app/srepl/fixes.clj +++ b/backend/src/app/srepl/fixes.clj @@ -16,8 +16,26 @@ [app.common.logging :as l] [app.common.uuid :as uuid] [app.db :as db] + [app.features.fdata :as feat.fdata] [app.srepl.helpers :as h])) +(defn disable-fdata-features + [{:keys [id features] :as file} _] + (when (or (contains? features "fdata/pointer-map") + (contains? features "fdata/objects-map")) + (l/warn :hint "disable fdata features" :file-id (str id)) + (-> file + (update :data feat.fdata/process-pointers deref) + (update :data feat.fdata/process-objects (partial into {})) + (update :features disj "fdata/pointer-map" "fdata/objects-map")))) + +(defn find-fdata-pointers + [{:keys [id features data] :as file} _] + (when (contains? features "fdata/pointer-map") + (let [pointers (feat.fdata/get-used-pointer-ids data)] + (l/warn :hint "found pointers" :file-id (str id) :pointers pointers) + nil))) + (defn repair-file-media "A helper intended to be used with `srepl.main/process-files!` that fixes all not propertly referenced file-media-object for a file" From c89a1b3b27023195e1384b697c062cea53488c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Fri, 9 Feb 2024 15:44:53 +0100 Subject: [PATCH 10/23] :bug: Fix extend button style in prototype tab --- .../styles/common/refactor/basic-rules.scss | 11 +- .../styles/common/refactor/design-tokens.scss | 4 + .../sidebar/options/menus/interactions.cljs | 4 +- .../sidebar/options/menus/interactions.scss | 288 +++++++++--------- 4 files changed, 164 insertions(+), 143 deletions(-) diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index 29a9219f0..83f2c904c 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -125,10 +125,11 @@ @include buttonStyle; @include flexCenter; @include focusTertiary; + --button-tertiary-border-width: $s-2; border-radius: $br-8; color: var(--button-tertiary-foreground-color-rest); background-color: transparent; - border: $s-2 solid transparent; + border: var(--button-tertiary-border-width) solid transparent; svg, span svg { stroke: var(--button-tertiary-foreground-color-rest); @@ -136,7 +137,7 @@ &:hover { background-color: var(--button-tertiary-background-color-hover); color: var(--button-tertiary-foreground-color-hover); - border: $s-2 solid var(--button-secondary-border-color-hover); + border-color: var(--button-secondary-border-color-hover); svg, span svg { stroke: var(--button-tertiary-foreground-color-hover); @@ -144,7 +145,7 @@ } &:active { outline: none; - border: $s-2 solid transparent; + border-color: transparent; background-color: var(--button-tertiary-background-color-active); color: var(--button-tertiary-foreground-color-active); svg, @@ -169,7 +170,7 @@ .button-icon-selected { outline: none; - border: $s-2 solid var(--button-icon-border-color-selected); + border-color: var(--button-icon-border-color-selected); background-color: var(--button-icon-background-color-selected); color: var(--button-icon-foreground-color-selected); svg { @@ -183,7 +184,7 @@ @include focusRadio; border-radius: $br-8; color: var(--button-radio-foreground-color-rest); - border: $s-1 solid var(--button-radio-background-color-rest); + border-color: $s-1 solid var(--button-radio-background-color-rest); svg, span svg { stroke: var(--button-radio-foreground-color-rest); diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index 67abb7774..799195f84 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -65,6 +65,9 @@ --button-tertiary-border-color-focus: var(--color-accent-primary); --button-tertiary-foreground-color-focus: var(--color-foreground-primary); + --expand-button-icon-border-width: 0; + --expand-button-icon-border-width-selected: 0; + --button-icon-foreground-color: var(--color-foreground-secondary); --button-icon-foreground-color-hover: var(--color-foreground-secondary); --button-icon-background-color-selected: var(--color-background-quaternary); @@ -396,4 +399,5 @@ --assets-item-name-foreground-color: var(--color-foreground-primary); --text-editor-selection-background-color: var(--la-tertiary-70); + --expand-button-icon-border-width-selected: 2px; } 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 c88dbc51b..f5f04bb7a 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 @@ -403,10 +403,10 @@ [:div {:class (stl/css-case :element-set-options-group true - :open extended-open?)} + :element-set-options-group-open extended-open?)} ; Summary [:div {:class (stl/css :interactions-summary)} - [:div {:class (stl/css-case :extend-btn true + [:button {:class (stl/css-case :extend-btn true :extended extended-open?) :on-click toggle-extended} i/menu-refactor] 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 cc3679140..09c1b4207 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 @@ -96,151 +96,167 @@ @include flexColumn($s-12); } -.element-set-options-group { - &.open { - @include flexColumn; - .extended-options { - @include flexColumn; - .property-row { - @extend .attr-row; - &.big-row { - height: 100%; - } - .interaction-name { - @include twoLineTextEllipsis; - @include titleTipography; - padding-left: $s-4; - width: $s-92; - margin: auto 0; - grid-area: name; - color: var(--title-foreground-color); - } - .select-wrapper { - display: flex; - align-items: center; - grid-area: content; - .easing-select { - width: $s-156; - padding: 0 $s-8; - .dropdown-upwards { - bottom: $s-36; - width: $s-156; - top: unset; - } - } - } - .input-element-wrapper { - @extend .input-element; - grid-area: content; - } - .checkbox-option { - @extend .input-checkbox; - grid-area: content; - } - .position-btns-wrapper { - grid-area: content; - display: grid; - grid-template-areas: - "topleft top topright" - "left center right" - "bottomleft bottom bottomright"; - grid-template-columns: repeat(3, 1fr); - grid-template-rows: repeat(3, 1fr); - width: $s-84; - height: $s-84; - border-radius: $br-8; - background-color: var(--color-background-tertiary); - .direction-btn { - @extend .button-tertiary; - height: $s-28; - width: $s-28; - .rectangle { - height: $s-8; - width: $s-8; - background-color: var(--color-background-quaternary); - } - &:hover { - .rectangle { - background-color: var(--color-accent-primary); - } - } - &.active { - background-color: var(--color-background-quaternary); - .rectangle { - background-color: var(--color-accent-primary); - } - } - } - .center-btn { - grid-area: center; - } - .top-left-btn { - grid-area: topleft; - } - .top-right-btn { - grid-area: topright; - } - .top-center-btn { - grid-area: top; - } - .bottom-left-btn { - grid-area: bottomleft; - } - .bottom-right-btn { - grid-area: bottomright; - } - .bottom-center-btn { - grid-area: bottom; - } - } - .buttons-wrapper { - grid-area: content; - .right svg { - transform: rotate(-90deg); - } - .left svg { - transform: rotate(90deg); - } - .up svg { - transform: rotate(180deg); - } - } - .inputs-wrapper { - grid-area: content; - @include flexRow; - .radio-btn { - @extend .input-checkbox; - } - } +.element-set-options-group-open { + @include flexColumn; +} + +.extended-options { + @include flexColumn; +} + +.property-row { + @extend .attr-row; + &.big-row { + height: 100%; + } + .interaction-name { + @include twoLineTextEllipsis; + @include titleTipography; + padding-left: $s-4; + width: $s-92; + margin: auto 0; + grid-area: name; + color: var(--title-foreground-color); + } + .select-wrapper { + display: flex; + align-items: center; + grid-area: content; + .easing-select { + width: $s-156; + padding: 0 $s-8; + .dropdown-upwards { + bottom: $s-36; + width: $s-156; + top: unset; } } } - - .interactions-summary { - @extend .asset-element; - height: $s-44; - padding: 0; - gap: $s-4; - .extend-btn { + .input-element-wrapper { + @extend .input-element; + grid-area: content; + } + .checkbox-option { + @extend .input-checkbox; + grid-area: content; + } + .position-btns-wrapper { + grid-area: content; + display: grid; + grid-template-areas: + "topleft top topright" + "left center right" + "bottomleft bottom bottomright"; + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(3, 1fr); + width: $s-84; + height: $s-84; + border-radius: $br-8; + background-color: var(--color-background-tertiary); + .direction-btn { @extend .button-tertiary; - height: 100%; + height: $s-28; width: $s-28; - svg { - @extend .button-icon; + .rectangle { + height: $s-8; + width: $s-8; + background-color: var(--color-background-quaternary); } - &.extended { - @extend .button-icon-selected; + &:hover { + .rectangle { + background-color: var(--color-accent-primary); + } + } + &.active { + background-color: var(--color-background-quaternary); + .rectangle { + background-color: var(--color-accent-primary); + } } } - - .remove-btn { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon-small; - } + .center-btn { + grid-area: center; } + .top-left-btn { + grid-area: topleft; + } + .top-right-btn { + grid-area: topright; + } + .top-center-btn { + grid-area: top; + } + .bottom-left-btn { + grid-area: bottomleft; + } + .bottom-right-btn { + grid-area: bottomright; + } + .bottom-center-btn { + grid-area: bottom; + } + } + .buttons-wrapper { + grid-area: content; + .right svg { + transform: rotate(-90deg); + } + .left svg { + transform: rotate(90deg); + } + .up svg { + transform: rotate(180deg); + } + } + .inputs-wrapper { + grid-area: content; + @include flexRow; + .radio-btn { + @extend .input-checkbox; + } + } +} + +.interactions-summary { + @extend .asset-element; + height: $s-44; + padding: 0; + gap: $s-8; + + .remove-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon-small; + } + } +} + +.extend-btn { + @extend .button-tertiary; + --button-tertiary-border-width: var(--expand-button-icon-border-width); + height: 100%; + width: $s-28; + border-end-end-radius: 0; + border-start-end-radius: 0; + padding: 0; + svg { + @extend .button-icon; + } + position: relative; + &:after { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-inline-end: $s-1 solid var(--panel-background-color); + } + &.extended { + @extend .button-icon-selected; + --button-tertiary-border-width: var(--expand-button-icon-border-width-selected); } } From 4e152f470b44ff7224e092e1b0cba21687e969bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Fri, 9 Feb 2024 16:22:59 +0100 Subject: [PATCH 11/23] :bug: Fix overaly checkboxes in prototype tab --- .../sidebar/options/menus/interactions.cljs | 8 ++++--- .../sidebar/options/menus/interactions.scss | 22 +++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) 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 f5f04bb7a..14b091461 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 @@ -573,7 +573,9 @@ [:span {:class (stl/css :rectangle)}]]]] ;; Overlay click outside - [:div {:class (stl/css :property-row)} + + [:ul {:class (stl/css :property-list)} + [:li {: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?)} @@ -587,7 +589,7 @@ :on-change change-close-click-outside}]]]] ;; Overlay background - [:div {:class (stl/css :property-row)} + [:li {:class (stl/css :property-row)} [:div {:class (stl/css :checkbox-option)} [:label {:for (str "background-" index) :class (stl/css-case :global/checked background-overlay?)} @@ -598,7 +600,7 @@ [:input {:type "checkbox" :id (str "background-" index) :checked background-overlay? - :on-change change-background-overlay}]]]]]) + :on-change change-background-overlay}]]]]]]) (when (ctsi/has-animation? interaction) [:* 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 09c1b4207..aa3989fe9 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 @@ -104,8 +104,17 @@ @include flexColumn; } +.property-list { + list-style: none; + margin: 0; + display: grid; + row-gap: $s-16; + margin-block: calc(#{$s-16} - #{$s-4}); +} + .property-row { @extend .attr-row; + height: auto; &.big-row { height: 100%; } @@ -136,10 +145,7 @@ @extend .input-element; grid-area: content; } - .checkbox-option { - @extend .input-checkbox; - grid-area: content; - } + .position-btns-wrapper { grid-area: content; display: grid; @@ -216,6 +222,14 @@ } } } +.checkbox-option { + @extend .input-checkbox; + grid-area: content; + line-height: 1.2; + label { + align-items: start; + } +} .interactions-summary { @extend .asset-element; From 2633e56a76821f3c047e285b0140389ca0f72675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Fri, 9 Feb 2024 16:25:40 +0100 Subject: [PATCH 12/23] :bug: Fix icon size in selects --- frontend/src/app/main/ui/components/select.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/components/select.scss b/frontend/src/app/main/ui/components/select.scss index 734fb3a40..e904c48ba 100644 --- a/frontend/src/app/main/ui/components/select.scss +++ b/frontend/src/app/main/ui/components/select.scss @@ -31,7 +31,7 @@ width: $s-24; padding-right: $s-4; svg { - @extend .button-icon; + @extend .button-icon-small; stroke: var(--icon-foreground); } } From c824711893fa2f7104440ee829b243603b04f86c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Fri, 9 Feb 2024 17:13:55 +0100 Subject: [PATCH 13/23] :bug: Replace overlay icons with new ones --- .../images/icons/corner-bottom-refactor.svg | 3 + .../icons/corner-bottomleft-refactor.svg | 3 + .../icons/corner-bottomright-refactor.svg | 3 + .../images/icons/corner-center-refactor.svg | 3 + .../images/icons/corner-top-refactor.svg | 3 + .../images/icons/corner-topleft-refactor.svg | 3 + .../images/icons/corner-topright-refactor.svg | 3 + .../styles/common/refactor/basic-rules.scss | 2 +- frontend/src/app/main/ui/icons.cljs | 7 ++ .../sidebar/options/menus/interactions.cljs | 95 +++++++-------- .../sidebar/options/menus/interactions.scss | 111 +++++++++--------- 11 files changed, 132 insertions(+), 104 deletions(-) create mode 100644 frontend/resources/images/icons/corner-bottom-refactor.svg create mode 100644 frontend/resources/images/icons/corner-bottomleft-refactor.svg create mode 100644 frontend/resources/images/icons/corner-bottomright-refactor.svg create mode 100644 frontend/resources/images/icons/corner-center-refactor.svg create mode 100644 frontend/resources/images/icons/corner-top-refactor.svg create mode 100644 frontend/resources/images/icons/corner-topleft-refactor.svg create mode 100644 frontend/resources/images/icons/corner-topright-refactor.svg diff --git a/frontend/resources/images/icons/corner-bottom-refactor.svg b/frontend/resources/images/icons/corner-bottom-refactor.svg new file mode 100644 index 000000000..ca2c80ea5 --- /dev/null +++ b/frontend/resources/images/icons/corner-bottom-refactor.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> + <path d="M15.333 14H.667"/> +</svg> diff --git a/frontend/resources/images/icons/corner-bottomleft-refactor.svg b/frontend/resources/images/icons/corner-bottomleft-refactor.svg new file mode 100644 index 000000000..ed9972420 --- /dev/null +++ b/frontend/resources/images/icons/corner-bottomleft-refactor.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> + <path d="M14 14H9.5A7.5 7.5 0 012 6.5V2"/> +</svg> diff --git a/frontend/resources/images/icons/corner-bottomright-refactor.svg b/frontend/resources/images/icons/corner-bottomright-refactor.svg new file mode 100644 index 000000000..8292d9bbc --- /dev/null +++ b/frontend/resources/images/icons/corner-bottomright-refactor.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> + <path d="M2 14h4.5A7.5 7.5 0 0014 6.5V2"/> +</svg> diff --git a/frontend/resources/images/icons/corner-center-refactor.svg b/frontend/resources/images/icons/corner-center-refactor.svg new file mode 100644 index 000000000..72b387bc0 --- /dev/null +++ b/frontend/resources/images/icons/corner-center-refactor.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> + <path d="M.667 8h14.666"/> +</svg> diff --git a/frontend/resources/images/icons/corner-top-refactor.svg b/frontend/resources/images/icons/corner-top-refactor.svg new file mode 100644 index 000000000..542f48376 --- /dev/null +++ b/frontend/resources/images/icons/corner-top-refactor.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> + <path d="M15.333 2H.667"/> +</svg> diff --git a/frontend/resources/images/icons/corner-topleft-refactor.svg b/frontend/resources/images/icons/corner-topleft-refactor.svg new file mode 100644 index 000000000..eeabf0c23 --- /dev/null +++ b/frontend/resources/images/icons/corner-topleft-refactor.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> + <path d="M14 2H9.5A7.499 7.499 0 002 9.5V14"/> +</svg> diff --git a/frontend/resources/images/icons/corner-topright-refactor.svg b/frontend/resources/images/icons/corner-topright-refactor.svg new file mode 100644 index 000000000..27454f142 --- /dev/null +++ b/frontend/resources/images/icons/corner-topright-refactor.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> + <path d="M2 2h4.5A7.499 7.499 0 0114 9.5V14"/> +</svg> diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index 83f2c904c..4dd70f856 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -125,7 +125,7 @@ @include buttonStyle; @include flexCenter; @include focusTertiary; - --button-tertiary-border-width: $s-2; + --button-tertiary-border-width: #{$s-2}; border-radius: $br-8; color: var(--button-tertiary-foreground-color-rest); background-color: transparent; diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index f65ff1676..edcb1016b 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -322,6 +322,13 @@ (def ^:icon column-reverse-refactor (icon-xref :column-reverse-refactor)) (def ^:icon constraint-horizontal-refactor (icon-xref :constraint-horizontal-refactor)) (def ^:icon constraint-vertical-refactor (icon-xref :constraint-vertical-refactor)) +(def ^:icon corner-bottom-refactor (icon-xref :corner-bottom-refactor)) +(def ^:icon corner-bottomleft-refactor (icon-xref :corner-bottomleft-refactor)) +(def ^:icon corner-bottomright-refactor (icon-xref :corner-bottom-refactor)) +(def ^:icon corner-center-refactor (icon-xref :corner-center-refactor)) +(def ^:icon corner-top-refactor (icon-xref :corner-top-refactor)) +(def ^:icon corner-topleft-refactor (icon-xref :corner-topleft-refactor)) +(def ^:icon corner-topright-refactor (icon-xref :corner-topright-refactor)) (def ^:icon corner-radius-refactor (icon-xref :corner-radius-refactor)) (def ^:icon curve-refactor (icon-xref :curve-refactor)) (def ^:icon distribute-vertical-spacing-refactor (icon-xref :distribute-vertical-spacing-refactor)) 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 14b091461..766a6b3c0 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 @@ -182,6 +182,21 @@ (when flow [:& flow-item {:flow flow :key (str (:id flow))}])]))) +(def ^:private corner-center-icon + (i/icon-xref :corner-center-refactor (stl/css :corner-icon))) +(def ^:private corner-bottom-icon + (i/icon-xref :corner-bottom-refactor (stl/css :corner-icon))) +(def ^:private corner-bottomleft-icon + (i/icon-xref :corner-bottomleft-refactor (stl/css :corner-icon))) +(def ^:private corner-bottomright-icon + (i/icon-xref :corner-bottomright-refactor (stl/css :corner-icon))) +(def ^:private corner-top-icon + (i/icon-xref :corner-top-refactor (stl/css :corner-icon))) +(def ^:private corner-topleft-icon + (i/icon-xref :corner-topleft-refactor (stl/css :corner-icon))) +(def ^:private corner-topright-icon + (i/icon-xref :corner-topright-refactor (stl/css :corner-icon))) + (mf/defc interaction-entry [{:keys [index shape interaction update-interaction remove-interaction]}] (let [objects (deref refs/workspace-page-objects) @@ -407,8 +422,8 @@ ; Summary [:div {:class (stl/css :interactions-summary)} [:button {:class (stl/css-case :extend-btn true - :extended extended-open?) - :on-click toggle-extended} + :extended extended-open?) + :on-click toggle-extended} i/menu-refactor] [:div {:class (stl/css :interactions-info) @@ -520,87 +535,75 @@ :active (= overlay-pos-type :center)) :data-value "center" :on-click toggle-overlay-pos-type} - [:span {:class (stl/css :rectangle)}]] + corner-center-icon] [: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)}]] + corner-topleft-icon] [: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)}]] + corner-topright-icon] [: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)}]] + corner-top-icon] [: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)}]] + corner-bottomleft-icon] [: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)}]] + corner-bottomright-icon] [: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)}]]]] + corner-bottom-icon]]] ;; Overlay click outside - [:ul {:class (stl/css :property-list)} - [:li {: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}]]]] + [:ul {:class (stl/css :property-list)} + [:li {: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 - [:li {: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}]]]]]]) + [:li {: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) [:* 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 aa3989fe9..f9eb79f54 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 @@ -145,63 +145,6 @@ @extend .input-element; grid-area: content; } - - .position-btns-wrapper { - grid-area: content; - display: grid; - grid-template-areas: - "topleft top topright" - "left center right" - "bottomleft bottom bottomright"; - grid-template-columns: repeat(3, 1fr); - grid-template-rows: repeat(3, 1fr); - width: $s-84; - height: $s-84; - border-radius: $br-8; - background-color: var(--color-background-tertiary); - .direction-btn { - @extend .button-tertiary; - height: $s-28; - width: $s-28; - .rectangle { - height: $s-8; - width: $s-8; - background-color: var(--color-background-quaternary); - } - &:hover { - .rectangle { - background-color: var(--color-accent-primary); - } - } - &.active { - background-color: var(--color-background-quaternary); - .rectangle { - background-color: var(--color-accent-primary); - } - } - } - .center-btn { - grid-area: center; - } - .top-left-btn { - grid-area: topleft; - } - .top-right-btn { - grid-area: topright; - } - .top-center-btn { - grid-area: top; - } - .bottom-left-btn { - grid-area: bottomleft; - } - .bottom-right-btn { - grid-area: bottomright; - } - .bottom-center-btn { - grid-area: bottom; - } - } .buttons-wrapper { grid-area: content; .right svg { @@ -222,6 +165,53 @@ } } } + +.position-btns-wrapper { + grid-area: content; + display: grid; + grid-template-areas: + "topleft top topright" + "left center right" + "bottomleft bottom bottomright"; + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(3, 1fr); + width: $s-84; + height: $s-84; + border-radius: $br-8; + background-color: var(--color-background-tertiary); + .center-btn { + grid-area: center; + } + .top-left-btn { + grid-area: topleft; + } + .top-right-btn { + grid-area: topright; + } + .top-center-btn { + grid-area: top; + } + .bottom-left-btn { + grid-area: bottomleft; + } + .bottom-right-btn { + grid-area: bottomright; + } + .bottom-center-btn { + grid-area: bottom; + } +} + +.direction-btn { + @extend .button-tertiary; + height: $s-28; + width: $s-28; + + &.active { + @extend .button-icon-selected; + } +} + .checkbox-option { @extend .input-checkbox; grid-area: content; @@ -274,6 +264,13 @@ } } +.corner-icon { + fill: none; + stroke: currentColor; + width: $s-12; + height: $s-12; +} + .flow-element { @include flexRow; } From 1415ed30b6e52c53e121f6714bee1c13c654d0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Tue, 13 Feb 2024 15:23:07 +0100 Subject: [PATCH 14/23] :bug: Fix icon not being shown when asset category had a zero count --- .../src/app/main/ui/components/title_bar.cljs | 4 +-- .../src/app/main/ui/components/title_bar.scss | 35 +++++++++++-------- .../ui/workspace/sidebar/assets/common.cljs | 1 + .../ui/workspace/sidebar/assets/common.scss | 2 +- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/frontend/src/app/main/ui/components/title_bar.cljs b/frontend/src/app/main/ui/components/title_bar.cljs index 61c664303..0c9899bbc 100644 --- a/frontend/src/app/main/ui/components/title_bar.cljs +++ b/frontend/src/app/main/ui/components/title_bar.cljs @@ -13,7 +13,7 @@ (mf/defc title-bar {::mf/wrap-props false} - [{:keys [collapsable collapsed on-collapsed title children on-btn-click btn-children class all-clickable]}] + [{:keys [collapsable collapsed on-collapsed title children on-btn-click btn-children class all-clickable add-icon-gap]}] (let [klass (dm/str (stl/css :title-bar) " " class)] [:div {:class klass} (if ^boolean collapsable @@ -33,7 +33,7 @@ :on-click on-collapsed} i/arrow-refactor] [:div {:class (stl/css :title)} title]])] - [:div {:class (stl/css :title-only)} title]) + [:div {:class (stl/css-case :title-only true :title-only-icon-gap add-icon-gap)} title]) children (when (some? on-btn-click) [:button {:class (stl/css :title-button) diff --git a/frontend/src/app/main/ui/components/title_bar.scss b/frontend/src/app/main/ui/components/title_bar.scss index 2ec13406b..e76b9fe2b 100644 --- a/frontend/src/app/main/ui/components/title_bar.scss +++ b/frontend/src/app/main/ui/components/title_bar.scss @@ -14,20 +14,6 @@ width: 100%; min-height: $s-32; background-color: var(--title-background-color); - .title, - .title-only { - @include tabTitleTipography; - display: flex; - align-items: center; - flex-grow: 1; - height: 100%; - min-height: $s-32; - color: var(--title-foreground-color); - overflow: hidden; - } - .title-only { - margin-left: $s-8; - } .title-wrapper { display: flex; @@ -109,3 +95,24 @@ } } } + +.title, +.title-only { + @include tabTitleTipography; + display: flex; + align-items: center; + flex-grow: 1; + height: 100%; + min-height: $s-32; + color: var(--title-foreground-color); + overflow: hidden; +} + +.title-only { + --title-bar-title-margin: #{$s-8}; + margin-inline-start: var(--title-bar-title-margin); +} + +.title-only-icon-gap { + --title-bar-title-margin: #{$s-12}; +} 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 d2f3ed1db..3ef6fb6ad 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs @@ -166,6 +166,7 @@ :collapsed (not open?) :all-clickable true :on-collapsed on-collapsed + :add-icon-gap (= 0 assets-count) :class (stl/css-case :title-spacing open?) :title title} buttons] 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 84d86bdc8..063cfa831 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss @@ -21,8 +21,8 @@ @include flexCenter; height: $s-16; width: $s-16; - color: transparent; fill: none; + stroke: currentColor; } } From bc3d268f57a7c9a6b4699341f557c64a028b1816 Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Tue, 13 Feb 2024 18:40:16 +0100 Subject: [PATCH 15/23] :sparkles: Add minor improvements to srepl helpers --- backend/src/app/srepl/fixes.clj | 7 ++++++ backend/src/app/srepl/main.clj | 42 ++++++--------------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/backend/src/app/srepl/fixes.clj b/backend/src/app/srepl/fixes.clj index 5e450e0d9..c5ba162f0 100644 --- a/backend/src/app/srepl/fixes.clj +++ b/backend/src/app/srepl/fixes.clj @@ -29,6 +29,13 @@ (update :data feat.fdata/process-objects (partial into {})) (update :features disj "fdata/pointer-map" "fdata/objects-map")))) +(def sql:get-fdata-files + "SELECT id FROM file + WHERE deleted_at is NULL + AND (features @> '{fdata/pointer-map}' OR + features @> '{fdata/objects-map}') + ORDER BY created_at DESC") + (defn find-fdata-pointers [{:keys [id features data] :as file} _] (when (contains? features "fdata/pointer-map") diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index 9851af8a3..ba9693e93 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -370,40 +370,11 @@ ;; PROCESSING ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(def ^:private - sql:get-file-ids +(def sql:get-files "SELECT id FROM file - WHERE created_at < ? AND deleted_at is NULL + WHERE deleted_at is NULL ORDER BY created_at DESC") -(defn analyze-files - "Apply a function to all files in the database, reading them in - batches. Do not change data. - - Emits rollback at the end of operation." - [on-file & {:keys [max-items start-at with-libraries?]}] - (letfn [(get-candidates [conn] - (cond->> (db/cursor conn [sql:get-file-ids (or start-at (dt/now))]) - (some? max-items) - (take max-items))) - - (process-file [{:keys [::db/conn] :as system} file-id] - (let [file (h/get-file system file-id) - libs (when with-libraries? - (->> (files/get-file-libraries conn file-id) - (into [file] (map (fn [{:keys [id]}] - (h/get-file system id)))) - (d/index-by :id)))] - (if with-libraries? - (on-file file libs) - (on-file file))))] - - (db/tx-run! (assoc main/system ::db/rollback true) - (fn [{:keys [::db/conn] :as system}] - (binding [h/*system* system] - (run! (partial process-file system) - (get-candidates conn))))))) - (defn process-file! "Apply a function to the file. Optionally save the changes or not. The function receives the decoded and migrated file data." @@ -435,11 +406,12 @@ "Apply a function to all files in the database" [update-fn & {:keys [max-items max-jobs - start-at - rollback?] + rollback? + query] :or {max-jobs 1 max-items Long/MAX_VALUE - rollback? true} + rollback? true + query sql:get-files} :as opts}] (l/dbg :hint "process:start" @@ -483,7 +455,7 @@ (px/run! executor (partial process-file file-id idx (dt/tpoint))) (inc idx)) 0 - (->> (db/cursor conn [sql:get-file-ids (or start-at (dt/now))]) + (->> (db/cursor conn [query] {:chunk-size 1}) (take max-items) (map :id))) (finally From afd68fa09d20ba56a479223c89aba567d797dada Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Tue, 13 Feb 2024 17:34:32 +0100 Subject: [PATCH 16/23] :bug: Properly handle fdata features on file-gc task It also adds a schema validation process after cleaning. If file does not validates it will be skiped. --- backend/src/app/binfile/common.clj | 3 - backend/src/app/tasks/file_gc.clj | 474 ++++++++++-------- backend/test/backend_tests/rpc_file_test.clj | 50 +- .../rpc_file_thumbnails_test.clj | 2 +- 4 files changed, 284 insertions(+), 245 deletions(-) diff --git a/backend/src/app/binfile/common.clj b/backend/src/app/binfile/common.clj index aceb4ef7b..4f9af0e7f 100644 --- a/backend/src/app/binfile/common.clj +++ b/backend/src/app/binfile/common.clj @@ -141,8 +141,6 @@ " WHERE flr.file_id = ANY(?) AND l.deleted_at IS NULL")] (db/exec! conn [sql ids]))))) - -;; NOTE: Will be used in future, commented for satisfy linter (def ^:private sql:get-libraries "WITH RECURSIVE libs AS ( SELECT fl.id @@ -409,7 +407,6 @@ (update :colors relink-colors) (d/without-nils)))))) - (defn- upsert-file! [conn file] (let [sql (str "INSERT INTO file (id, project_id, name, revn, is_shared, data, created_at, modified_at) " diff --git a/backend/src/app/tasks/file_gc.clj b/backend/src/app/tasks/file_gc.clj index b5b9e4dd9..031bf357a 100644 --- a/backend/src/app/tasks/file_gc.clj +++ b/backend/src/app/tasks/file_gc.clj @@ -11,7 +11,8 @@ inactivity (the default threshold is 72h)." (:require [app.binfile.common :as bfc] - [app.common.files.migrations :as pmg] + [app.common.files.migrations :as fmg] + [app.common.files.validate :as cfv] [app.common.logging :as l] [app.common.thumbnails :as thc] [app.common.types.components-list :as ctkl] @@ -29,9 +30,256 @@ [clojure.spec.alpha :as s] [integrant.core :as ig])) -(declare ^:private get-candidates) (declare ^:private clean-file!) +(defn- decode-file + [cfg {:keys [id] :as file}] + (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)] + (-> file + (update :features db/decode-pgarray #{}) + (update :data blob/decode) + (update :data feat.fdata/process-pointers deref) + (update :data feat.fdata/process-objects (partial into {})) + (update :data assoc :id id) + (fmg/migrate-file)))) + +(defn- update-file! + [{:keys [::db/conn] :as cfg} {:keys [id] :as file}] + (let [file (if (contains? (:features file) "fdata/objects-map") + (feat.fdata/enable-objects-map file) + file) + + file (if (contains? (:features file) "fdata/pointer-map") + (binding [pmap/*tracked* (pmap/create-tracked)] + (let [file (feat.fdata/enable-pointer-map file)] + (feat.fdata/persist-pointers! cfg id) + file)) + file) + + file (-> file + (update :features db/encode-pgarray conn "text") + (update :data blob/encode))] + + (db/update! conn :file + {:has-media-trimmed true + :data (:data file)} + {:id id}))) + +(defn- process-file! + [cfg file] + (try + (let [file (decode-file cfg file) + file (clean-file! cfg file)] + (cfv/validate-file-schema! file) + (update-file! cfg file)) + (catch Throwable cause + (l/err :hint "error on cleaning file (skiping)" + :file-id (str (:id file)) + :cause cause)))) + +(def ^:private + 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 + 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 (str file-id)) + (db/query conn :file {:id file-id})) + + (let [min-age (db/interval min-age)] + (db/cursor conn [sql:get-candidates min-age] {:chunk-size 1})))) + +(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." + [{:keys [::db/conn]} {:keys [id data] :as file}] + (let [used (bfc/collect-used-media data) + ids (db/create-array conn "uuid" used) + unused (->> (db/exec! conn [sql:mark-file-media-object-deleted id ids]) + (into #{} (map :id)))] + + (doseq [id unused] + (l/trc :hint "mark deleted" + :rel "file-media-object" + :id (str id) + :file-id (str id))) + + [(count unused) file])) + +(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]} {:keys [data] :as file}] + (let [file-id (:id file) + 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"))))))) + + ids (db/create-array conn "text" using) + unused (->> (db/exec! conn [sql:mark-file-object-thumbnails-deleted file-id ids]) + (into #{} (map :object-id)))] + + (doseq [object-id unused] + (l/trc :hint "mark deleted" + :rel "file-tagged-object-thumbnail" + :object-id object-id + :file-id (str file-id))) + + [(count unused) file])) + +(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]} {:keys [id revn] :as file}] + (let [unused (->> (db/exec! conn [sql:mark-file-thumbnails-deleted id revn]) + (into #{} (map :revn)))] + + (doseq [revn unused] + (l/trc :hint "mark deleted" + :rel "file-thumbnail" + :revn revn + :file-id (str id))) + + [(count unused) file])) + + +(def ^:private sql:get-files-for-library + "SELECT f.id, f.data, f.modified_at, f.features + 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." + [{:keys [::db/conn] :as cfg} {:keys [data] :as file}] + (let [file-id (:id file) + + get-used-components + (fn [data components] + ;; Find which of the components are used in the file. + (into #{} + (filter #(ctf/used-in? data file-id % :component)) + components)) + + get-unused-components + (fn [components files] + ;; Find and return a set of unused components (on all files). + (reduce (fn [components {:keys [data]}] + (if (seq components) + (->> (get-used-components data components) + (set/difference components)) + (reduced components))) + + components + files)) + + process-fdata + (fn [data unused] + (reduce (fn [data id] + (l/trc :hint "delete component" + :component-id (str id) + :file-id (str file-id)) + (ctkl/delete-component data id)) + data + unused)) + + deleted (into #{} (ctkl/deleted-components-seq data)) + + unused (->> (db/cursor conn [sql:get-files-for-library file-id] {:chunk-size 1}) + (map (partial decode-file cfg)) + (cons file) + (get-unused-components deleted) + (mapv :id) + (set)) + + file (update file :data process-fdata unused)] + + [(count unused) file])) + +(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! + [{:keys [::db/conn]} {:keys [id data] :as file}] + (let [used (->> (db/cursor conn [sql:get-changes id]) + (into (feat.fdata/get-used-pointer-ids data) + (comp (map :data) + (map blob/decode) + (mapcat feat.fdata/get-used-pointer-ids)))) + + unused (let [ids (db/create-array conn "uuid" used)] + (->> (db/exec! conn [sql:mark-deleted-data-fragments id ids]) + (into #{} (map :id))))] + + (doseq [id unused] + (l/trc :hint "mark deleted" + :rel "file-data-fragment" + :id (str id) + :file-id (str id))) + + [(count unused) file])) + +(defn- clean-file! + [cfg {:keys [id] :as file}] + (let [[n1 file] (clean-file-media! cfg file) + [n2 file] (clean-file-thumbnails! cfg file) + [n3 file] (clean-file-object-thumbnails! cfg file) + [n4 file] (clean-deleted-components! cfg file) + [n5 file] (clean-data-fragments! cfg file)] + + (l/dbg :hint "file clened" + :file-id (str id) + :modified-at (dt/format-instant (:modified-at file)) + :media-objects n1 + :thumbnails n2 + :object-thumbnails n3 + :components n4 + :data-fragments n5) + + file)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; HANDLER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -55,7 +303,7 @@ (assoc ::min-age min-age)) total (reduce (fn [total file] - (clean-file! cfg file) + (process-file! cfg file) (inc total)) 0 (get-candidates cfg))] @@ -69,223 +317,3 @@ (db/rollback! conn)) {:processed total}))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; IMPL -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(def ^:private - 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 - 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 (str file-id)) - (->> (db/query conn :file {:id file-id}) - (map #(update % :features db/decode-pgarray #{})))) - - (let [min-age (db/interval min-age)] - (->> (db/cursor conn [sql:get-candidates min-age] {:chunk-size 1}) - (map #(update % :features db/decode-pgarray #{})))))) - -(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 (bfc/collect-used-media data) - ids (db/create-array conn "uuid" used) - unused (->> (db/exec! conn [sql:mark-file-media-object-deleted file-id ids]) - (into #{} (map :id)))] - - (doseq [id unused] - (l/trc :hint "mark deleted" - :rel "file-media-object" - :id (str id) - :file-id (str file-id))) - - (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]} 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"))))))) - - ids (db/create-array conn "text" using) - unused (->> (db/exec! conn [sql:mark-file-object-thumbnails-deleted file-id ids]) - (into #{} (map :object-id)))] - - (doseq [object-id unused] - (l/trc :hint "mark deleted" - :rel "file-tagged-object-thumbnail" - :object-id object-id - :file-id (str file-id))) - - (count unused))) - - -(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]} file-id revn] - (let [unused (->> (db/exec! conn [sql:mark-file-thumbnails-deleted file-id revn]) - (into #{} (map :revn)))] - - (doseq [revn unused] - (l/trc :hint "mark deleted" - :rel "file-thumbnail" - :revn revn - :file-id (str file-id))) - - (count unused))) - - -(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." - [{: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)) - components)) - - (get-unused-components [components files-data] - ;; Find and return a set of unused components (on all files). - (reduce (fn [components fdata] - (if (seq components) - (->> (get-used-components fdata components) - (set/difference components)) - (reduced components))) - - components - files-data))] - - (let [deleted (into #{} (ctkl/deleted-components-seq data)) - 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))] - - (doseq [id unused] - (l/trc :hint "delete component" :component-id (str id) :file-id (str file-id))) - - - (when-let [data (some->> (seq unused) - (reduce ctkl/delete-component data) - (blob/encode))] - (db/update! conn :file - {:data data} - {:id file-id})) - - (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] - (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)))) - - unused (let [ids (db/create-array conn "uuid" used)] - (->> (db/exec! conn [sql:mark-deleted-data-fragments file-id ids]) - (into #{} (map :id))))] - - (doseq [id unused] - (l/trc :hint "mark deleted" - :rel "file-data-fragment" - :id (str id) - :file-id (str file-id))) - - (count unused))) - - -(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)) - - 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)] - - (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}) - - (feat.fdata/persist-pointers! cfg id)))) diff --git a/backend/test/backend_tests/rpc_file_test.clj b/backend/test/backend_tests/rpc_file_test.clj index 510aadd89..a684227c8 100644 --- a/backend/test/backend_tests/rpc_file_test.clj +++ b/backend/test/backend_tests/rpc_file_test.clj @@ -154,7 +154,7 @@ ;; Check the number of fragments before adding the page (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] - (t/is (= 1 (count rows)))) + (t/is (= 2 (count rows)))) ;; Add page (update-file! @@ -172,15 +172,15 @@ ;; Check the number of fragments (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] - (t/is (= 2 (count rows)))) + (t/is (= 5 (count rows)))) ;; The objects-gc should remove unused fragments (let [res (th/run-task! :objects-gc {:min-age 0})] - (t/is (= 0 (:processed res)))) + (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)))) + (t/is (= 4 (count rows)))) ;; Add shape to page that should add a new fragment (update-file! @@ -203,7 +203,7 @@ ;; Check the number of fragments (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] - (t/is (= 3 (count rows)))) + (t/is (= 5 (count rows)))) ;; The file-gc should mark for remove unused fragments (let [res (th/run-task! :file-gc {:min-age 0})] @@ -211,12 +211,13 @@ ;; The objects-gc should remove unused fragments (let [res (th/run-task! :objects-gc {:min-age 0})] - (t/is (= 0 (:processed res)))) + (t/is (= 1 (:processed res)))) ;; Check the number of fragments; should be 3 because changes ;; are also holding pointers to fragments; - (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] - (t/is (= 3 (count rows)))) + (let [rows (th/db-query :file-data-fragment {:file-id (:id file) + :deleted-at nil})] + (t/is (= 6 (count rows)))) ;; Lets proceed to delete all changes (th/db-delete! :file-change {:file-id (:id file)}) @@ -224,7 +225,6 @@ {:has-media-trimmed false} {:id (:id file)}) - ;; The file-gc should remove fragments related to changes ;; snapshots previously deleted. (let [res (th/run-task! :file-gc {:min-age 0})] @@ -233,11 +233,11 @@ ;; Check the number of fragments; (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] ;; (pp/pprint rows) - (t/is (= 3 (count rows))) + (t/is (= 8 (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)))) + (t/is (= 6 (:processed res)))) (let [rows (th/db-query :file-data-fragment {:file-id (:id file)})] (t/is (= 2 (count rows))))))) @@ -367,7 +367,7 @@ (t/is (= 1 (:processed res)))) (let [res (th/run-task! :objects-gc {:min-age 0})] - (t/is (= 1 (:processed res)))) + (t/is (= 2 (: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 @@ -432,6 +432,11 @@ page-id (first (get-in file [:data :pages]))] + + (let [rows (th/db-query :file-data-fragment {:file-id (:id file) + :deleted-at nil})] + (t/is (= (count rows) 1))) + ;; Update file inserting a new image object (update-file! :file-id (:id file) @@ -491,6 +496,10 @@ (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) + :deleted-at nil})] + (t/is (= (count rows) 2))) + ;; retrieve file and check trimmed attribute (let [row (th/db-get :file {:id (:id file)})] (t/is (true? (:has-media-trimmed row)))) @@ -521,11 +530,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 [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)))) + (t/is (= 6 (:processed res)))) + + (let [rows (th/db-query :file-data-fragment {:file-id (:id file) + :deleted-at nil})] + (t/is (= (count rows) 3))) ;; Now that file-gc have deleted the file-media-object usage, ;; lets execute the touched-gc task, we should see that two of @@ -681,7 +695,6 @@ (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)))) @@ -689,7 +702,7 @@ ;; 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)))) + (t/is (= 3 (:processed res)))) ;; Now that objects-gc have deleted the object thumbnail lets ;; execute the touched-gc task @@ -719,7 +732,7 @@ (let [res (th/run-task! :objects-gc {:min-age 0})] ;; (pp/pprint res) - (t/is (= 1 (:processed res)))) + (t/is (= 2 (:processed res)))) ;; We still have th storage objects in the table (let [rows (th/db-query :storage-object {:deleted-at nil})] @@ -736,6 +749,7 @@ ;; (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) @@ -1147,7 +1161,7 @@ (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)))) + (t/is (= 3 (:processed res)))) (let [rows (th/db-query :file-tagged-object-thumbnail {:file-id (:id file)})] (t/is (= 1 (count rows))))))) @@ -1203,7 +1217,7 @@ (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)))) + (t/is (= 2 (: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 88e2ac2d2..1ad3c6e09 100644 --- a/backend/test/backend_tests/rpc_file_thumbnails_test.clj +++ b/backend/test/backend_tests/rpc_file_thumbnails_test.clj @@ -222,7 +222,7 @@ (t/is (= 1 (:processed result)))) (let [result (th/run-task! :objects-gc {:min-age 0})] - (t/is (= 1 (:processed result)))) + (t/is (= 2 (:processed result)))) ;; check if row1 related thumbnail row still exists (let [[row :as rows] (th/db-query :file-thumbnail From 8ea82021f032cbd4c77d6312f7f5edb1ec6f744a Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Tue, 13 Feb 2024 18:17:43 +0100 Subject: [PATCH 17/23] :sparkles: Add better error report on importing truncated binfile --- backend/src/app/binfile/v1.clj | 7 +++++++ backend/src/app/http/sse.clj | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/src/app/binfile/v1.clj b/backend/src/app/binfile/v1.clj index 207b40ec9..8597254c7 100644 --- a/backend/src/app/binfile/v1.clj +++ b/backend/src/app/binfile/v1.clj @@ -40,6 +40,7 @@ [promesa.util :as pu] [yetti.adapter :as yt]) (:import + com.github.luben.zstd.ZstdIOException com.github.luben.zstd.ZstdInputStream com.github.luben.zstd.ZstdOutputStream java.io.DataInputStream @@ -756,6 +757,12 @@ (pu/with-open [input (io/input-stream input)] (read-import! (assoc cfg ::input input)))) + (catch ZstdIOException cause + (ex/raise :type :validation + :code :invalid-penpot-file + :hint "invalid penpot file received: probably truncated" + :cause cause)) + (catch Throwable cause (vreset! cs cause) (throw cause)) diff --git a/backend/src/app/http/sse.clj b/backend/src/app/http/sse.clj index ec80df72d..868801091 100644 --- a/backend/src/app/http/sse.clj +++ b/backend/src/app/http/sse.clj @@ -61,9 +61,6 @@ (let [result (handler)] (events/tap :end result)) (catch Throwable cause - (binding [l/*context* (errors/request->context request)] - (l/err :hint "unexpected error process streaming response" - :cause cause)) (events/tap :error (errors/handle' cause request))) (finally (sp/close! events/*channel*) From f152e307370f34005dde6c12834cbcf9eada0fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Tue, 13 Feb 2024 14:55:08 +0100 Subject: [PATCH 18/23] :bug: Fix shortcuts menu being clipped --- .../main/ui/workspace/sidebar/shortcuts.scss | 351 +++++++++--------- 1 file changed, 179 insertions(+), 172 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss index acd82fd10..530de5577 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss @@ -7,195 +7,202 @@ @import "refactor/common-refactor.scss"; .shortcuts { - .shortcuts-header { - @include flexCenter; - @include tabTitleTipography; - position: relative; - height: $s-32; - padding: $s-2 $s-2 $s-2 0; - margin: $s-4 $s-4 0 $s-4; - border-radius: $br-6; - background-color: var(--panel-title-background-color); + display: grid; + grid-template-rows: auto auto 1fr; + // TODO: Fix this once we start implementing the DS. + // We should not be doign these hardcoded calc's. + height: calc(100vh - #{$s-60}); +} - .shortcuts-title { - @include flexCenter; - flex-grow: 1; - color: var(--title-foreground-color-hover); - } - - .shortcuts-close-button { - @extend .button-tertiary; - position: absolute; - right: $s-2; - top: $s-2; - height: $s-28; - width: $s-28; - border-radius: $br-5; - - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - } - } - - .search-field { - display: flex; +.search-field { + display: flex; + align-items: center; + height: $s-32; + margin: $s-16 $s-12 $s-4 $s-12; + border-radius: $br-8; + font-family: "worksans", sans-serif; + background-color: var(--color-background-tertiary); + .search-box { align-items: center; - height: $s-32; - margin: $s-16 $s-12 $s-4 $s-12; - border-radius: $br-8; - font-family: "worksans", sans-serif; - background-color: var(--color-background-tertiary); - .search-box { - align-items: center; + display: flex; + width: 100%; + + .icon-wrapper { display: flex; - width: 100%; - - .icon-wrapper { - display: flex; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - - .input-text { - @include removeInputStyle; - height: $s-32; - width: 100%; - margin: 0; - padding: $s-4; - border: 0; - font-size: $fs-12; - color: var(--color-foreground-primary); - &::placeholder { - color: var(--color-foreground-secondary); - } - &:focus-visible { - border-color: var(--color-accent-primary-muted); - } - } - .clear-btn { - @include buttonStyle; - @include flexCenter; - height: $s-16; - width: $s-16; - .clear-icon { - @include flexCenter; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - } - } - .search-icon { - @include flexCenter; - width: $s-28; svg { @extend .button-icon-small; stroke: var(--icon-foreground); } } - } - .section { - margin: 0; - } - .shortcuts-list { - display: flex; - flex-direction: column; - height: 90%; - padding: $s-12; - margin-bottom: $s-12; - overflow-y: overlay; - font-size: $fs-12; - color: var(--title-foreground-color); - - .section-title, - .subsection-title { - @include tabTitleTipography; - display: flex; - align-items: center; + .input-text { + @include removeInputStyle; + height: $s-32; + width: 100%; margin: 0; - padding: $s-8 0; - cursor: pointer; - - .collapsed-shortcuts { + padding: $s-4; + border: 0; + font-size: $fs-12; + color: var(--color-foreground-primary); + &::placeholder { + color: var(--color-foreground-secondary); + } + &:focus-visible { + border-color: var(--color-accent-primary-muted); + } + } + .clear-btn { + @include buttonStyle; + @include flexCenter; + height: $s-16; + width: $s-16; + .clear-icon { @include flexCenter; svg { @extend .button-icon-small; stroke: var(--icon-foreground); } - &.open { - transform: rotate(90deg); - } - } - .subsection-name, - .section-name { - padding-left: $s-4; - } - &:hover { - color: var(--title-foreground-color-hover); - .collapsed-shortcuts { - svg { - stroke: var(--title-foreground-color-hover); - } - } - } - } - - .subsection-title { - text-transform: none; - padding-left: $s-12; - } - .subsection-menu { - margin-bottom: $s-4; - } - .sub-menu { - margin-bottom: $s-4; - - .shortcuts-name { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - min-height: $s-32; - padding: $s-6; - margin-bottom: $s-4; - border-radius: $br-8; - background-color: var(--pill-background-color); - - .command-name { - @include titleTipography; - margin-left: $s-2; - color: var(--pill-foreground-color); - } - .keys { - @include flexCenter; - gap: $s-2; - color: var(--pill-foreground-color); - - .key { - @include titleTipography; - @include flexCenter; - text-transform: capitalize; - height: $s-20; - padding: $s-2 $s-6; - border-radius: $s-6; - background-color: var(--menu-shortcut-background-color); - } - .space { - margin: 0 $s-2; - } - } } } } - .not-found { - @include titleTipography; - color: var(--empty-message-foreground-color); - margin: $s-12; + .search-icon { + @include flexCenter; + width: $s-28; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } + } +} + +.shortcuts-header { + @include flexCenter; + @include tabTitleTipography; + position: relative; + height: $s-32; + padding: $s-2 $s-2 $s-2 0; + margin: $s-4 $s-4 0 $s-4; + border-radius: $br-6; + background-color: var(--panel-title-background-color); + + .shortcuts-title { + @include flexCenter; + flex-grow: 1; + color: var(--title-foreground-color-hover); + } + + .shortcuts-close-button { + @extend .button-tertiary; + position: absolute; + right: $s-2; + top: $s-2; + height: $s-28; + width: $s-28; + border-radius: $br-5; + + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + } +} + +.section { + margin: 0; +} + +.not-found { + @include titleTipography; + color: var(--empty-message-foreground-color); + margin: $s-12; +} + +.shortcuts-list { + display: flex; + flex-direction: column; + height: 100%; + padding: $s-12; + overflow-y: scroll; + font-size: $fs-12; + color: var(--title-foreground-color); + + .section-title, + .subsection-title { + @include tabTitleTipography; + display: flex; + align-items: center; + margin: 0; + padding: $s-8 0; + cursor: pointer; + + .collapsed-shortcuts { + @include flexCenter; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } + &.open { + transform: rotate(90deg); + } + } + .subsection-name, + .section-name { + padding-left: $s-4; + } + &:hover { + color: var(--title-foreground-color-hover); + .collapsed-shortcuts { + svg { + stroke: var(--title-foreground-color-hover); + } + } + } + } + + .subsection-title { + text-transform: none; + padding-left: $s-12; + } + .subsection-menu { + margin-bottom: $s-4; + } + .sub-menu { + margin-bottom: $s-4; + + .shortcuts-name { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + min-height: $s-32; + padding: $s-6; + margin-bottom: $s-4; + border-radius: $br-8; + background-color: var(--pill-background-color); + + .command-name { + @include titleTipography; + margin-left: $s-2; + color: var(--pill-foreground-color); + } + .keys { + @include flexCenter; + gap: $s-2; + color: var(--pill-foreground-color); + + .key { + @include titleTipography; + @include flexCenter; + text-transform: capitalize; + height: $s-20; + padding: $s-2 $s-6; + border-radius: $s-6; + background-color: var(--menu-shortcut-background-color); + } + .space { + margin: 0 $s-2; + } + } + } } } From d654a4faedc2917fb3162f2e469e3c8792167014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= <andres.moya@kaleidos.net> Date: Tue, 13 Feb 2024 14:43:30 +0100 Subject: [PATCH 19/23] :bug: Avoid setting touched in parent when swapping components --- .../src/app/common/files/changes_builder.cljc | 13 ++++++++----- .../app/main/data/workspace/libraries.cljs | 3 ++- .../src/app/main/data/workspace/shapes.cljs | 19 +++++++++---------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index f5d1cf201..f868cbd2a 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -326,7 +326,9 @@ (some? index) (assoc :index index) (:component-swap options) - (assoc :component-swap true)) + (assoc :component-swap true) + (:ignore-touched options) + (assoc :ignore-touched true)) mk-undo-change (fn [undo-changes shape] @@ -450,10 +452,11 @@ add-redo-change (fn [change-set id] (conj change-set - {:type :del-obj - :page-id page-id - :ignore-touched ignore-touched - :id id})) + (cond-> {:type :del-obj + :page-id page-id + :id id} + ignore-touched + (assoc :ignore-touched true)))) add-undo-change-shape (fn [change-set id] diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 1fab0ddcd..5edcafbe0 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -898,7 +898,8 @@ (pcb/update-shapes [(:id new-shape)] #(d/patch-object % keep-props-values)) ;; We need to set the same index as the original shape - (pcb/change-parent (:parent-id shape) [new-shape] index {:component-swap true}))] + (pcb/change-parent (:parent-id shape) [new-shape] index {:component-swap true + :ignore-touched true}))] ;; First delete so we don't break the grid layout cells (rx/of (dch/commit-changes changes) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 99e13369a..805669e4d 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -142,17 +142,17 @@ (rx/concat (rx/of (dwu/start-undo-transaction undo-id) (update-shape-flags ids-to-hide {:hidden true})) - (real-delete-shapes file page objects ids-to-delete it components-v2) + (real-delete-shapes file page objects ids-to-delete it components-v2 (:component-swap options)) (rx/of (dwu/commit-undo-transaction undo-id)))))))) (defn- real-delete-shapes-changes - ([file page objects ids it components-v2] + ([file page objects ids it components-v2 ignore-touched] (let [changes (-> (pcb/empty-changes it (:id page)) (pcb/with-page page) (pcb/with-objects objects) (pcb/with-library-data file))] - (real-delete-shapes-changes changes file page objects ids it components-v2))) - ([changes file page objects ids _it components-v2] + (real-delete-shapes-changes changes file page objects ids it components-v2 ignore-touched))) + ([changes file page objects ids _it components-v2 ignore-touched] (let [lookup (d/getf objects) groups-to-unmask (reduce (fn [group-ids id] @@ -252,7 +252,7 @@ changes (-> changes (pcb/remove-objects all-children {:ignore-touched true}) - (pcb/remove-objects ids) + (pcb/remove-objects ids {:ignore-touched ignore-touched}) (pcb/remove-objects empty-parents) (pcb/resize-parents all-parents) (pcb/update-shapes groups-to-unmask @@ -274,13 +274,13 @@ (defn delete-shapes-changes - [changes file page objects ids it components-v2] - (let [[changes _all-parents] (real-delete-shapes-changes changes file page objects ids it components-v2)] + [changes file page objects ids it components-v2 ignore-touched] + (let [[changes _all-parents] (real-delete-shapes-changes changes file page objects ids it components-v2 ignore-touched)] changes)) (defn- real-delete-shapes - [file page objects ids it components-v2] - (let [[changes all-parents] (real-delete-shapes-changes file page objects ids it components-v2) + [file page objects ids it components-v2 ignore-touched] + (let [[changes all-parents] (real-delete-shapes-changes file page objects ids it components-v2 ignore-touched) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) (dc/detach-comment-thread ids) @@ -288,7 +288,6 @@ (ptk/data-event :layout/update all-parents) (dwu/commit-undo-transaction undo-id)))) - (defn create-and-add-shape [type frame-x frame-y {:keys [width height] :as attrs}] (ptk/reify ::create-and-add-shape From fa19ce2b5b90298fa639718949a9c498ce08326f Mon Sep 17 00:00:00 2001 From: Alejandro Alonso <alejandroalonsofernandez@gmail.com> Date: Wed, 14 Feb 2024 07:58:21 +0100 Subject: [PATCH 20/23] :bug: Fix change stroke color from library doesn't work --- frontend/src/app/main/data/workspace/colors.cljs | 4 ++-- frontend/src/app/main/ui/workspace/colorpicker.cljs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 1d4afbd9b..7c31ef43b 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -442,6 +442,7 @@ (declare activate-colorpicker-color) (declare activate-colorpicker-gradient) (declare activate-colorpicker-image) +(declare update-colorpicker) (defn apply-color-from-colorpicker [color] @@ -453,8 +454,7 @@ (:image color) (activate-colorpicker-image) (:color color) (activate-colorpicker-color) (= :linear (get-in color [:gradient :type])) (activate-colorpicker-gradient :linear-gradient) - (= :radial (get-in color [:gradient :type])) (activate-colorpicker-gradient :radial-gradient)) - (apply-color-from-palette color false))))) + (= :radial (get-in color [:gradient :type])) (activate-colorpicker-gradient :radial-gradient)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index c98caaa6c..e74f83525 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -145,7 +145,8 @@ on-select-library-color (mf/use-fn (fn [_ color] - (st/emit! (dc/apply-color-from-colorpicker color)))) + (st/emit! (dc/apply-color-from-colorpicker color)) + (on-change color))) on-add-library-color (mf/use-fn From 8ead63cad0ad653009938a31de37eb29ef572a14 Mon Sep 17 00:00:00 2001 From: Eva <eva.marco@kaleidos.net> Date: Wed, 7 Feb 2024 19:43:52 +0100 Subject: [PATCH 21/23] :recycle: Review inspect tab spacing --- .../styles/common/refactor/mixins.scss | 4 +- .../app/main/ui/components/color_bullet.cljs | 2 +- .../main/ui/components/color_bullet_new.cljs | 18 +- .../main/ui/components/color_bullet_new.scss | 4 + .../app/main/ui/components/copy_button.scss | 30 ++-- .../src/app/main/ui/components/select.cljs | 10 +- .../src/app/main/ui/components/title_bar.cljs | 7 +- .../src/app/main/ui/components/title_bar.scss | 107 ++++++----- .../main/ui/viewer/inspect/attributes.scss | 1 + .../ui/viewer/inspect/attributes/blur.cljs | 8 +- .../ui/viewer/inspect/attributes/blur.scss | 4 + .../ui/viewer/inspect/attributes/common.cljs | 167 ++++++++++-------- .../ui/viewer/inspect/attributes/common.scss | 87 ++++++--- .../ui/viewer/inspect/attributes/fill.cljs | 2 +- .../ui/viewer/inspect/attributes/fill.scss | 5 + .../viewer/inspect/attributes/geometry.cljs | 19 +- .../viewer/inspect/attributes/geometry.scss | 4 + .../ui/viewer/inspect/attributes/image.cljs | 2 +- .../ui/viewer/inspect/attributes/layout.cljs | 21 ++- .../ui/viewer/inspect/attributes/layout.scss | 4 + .../inspect/attributes/layout_element.cljs | 17 +- .../inspect/attributes/layout_element.scss | 4 + .../ui/viewer/inspect/attributes/shadow.cljs | 2 + .../ui/viewer/inspect/attributes/stroke.cljs | 1 + .../ui/viewer/inspect/attributes/stroke.scss | 5 + .../ui/viewer/inspect/attributes/svg.cljs | 21 ++- .../ui/viewer/inspect/attributes/text.cljs | 7 +- .../ui/viewer/inspect/attributes/text.scss | 2 +- .../src/app/main/ui/viewer/inspect/code.cljs | 38 ++-- .../src/app/main/ui/viewer/inspect/code.scss | 23 ++- .../main/ui/viewer/inspect/right_sidebar.scss | 10 +- .../app/main/ui/workspace/color_palette.cljs | 2 +- .../src/app/main/ui/workspace/sidebar.scss | 7 +- .../app/main/ui/workspace/sidebar/layers.scss | 3 +- frontend/translations/en.po | 3 + frontend/translations/es.po | 3 + 36 files changed, 403 insertions(+), 251 deletions(-) diff --git a/frontend/resources/styles/common/refactor/mixins.scss b/frontend/resources/styles/common/refactor/mixins.scss index f988cd0df..2b9a05efd 100644 --- a/frontend/resources/styles/common/refactor/mixins.scss +++ b/frontend/resources/styles/common/refactor/mixins.scss @@ -115,8 +115,8 @@ @mixin copyWrapperBase { position: relative; min-height: $s-32; - width: $s-156; - max-width: $s-156; + width: $s-144; + max-width: $s-144; padding: calc($s-8 - $s-1) 0 calc($s-8 - $s-1) calc($s-8 - $s-1); border-radius: $s-8; box-sizing: border-box; diff --git a/frontend/src/app/main/ui/components/color_bullet.cljs b/frontend/src/app/main/ui/components/color_bullet.cljs index 0b273aac2..7213a8347 100644 --- a/frontend/src/app/main/ui/components/color_bullet.cljs +++ b/frontend/src/app/main/ui/components/color_bullet.cljs @@ -57,5 +57,5 @@ :on-double-click on-double-click :title name} (if (some? image) - (tr "media.image") + (tr "media.image.short") (or name color (uc/gradient-type->string (:type gradient))))]))) 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 ff333f35e..6173a582f 100644 --- a/frontend/src/app/main/ui/components/color_bullet_new.cljs +++ b/frontend/src/app/main/ui/components/color_bullet_new.cljs @@ -9,7 +9,7 @@ (:require [app.config :as cfg] [app.util.color :as uc] - [app.util.i18n :as i18n :refer [tr]] + [app.util.i18n :refer [tr]] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -99,16 +99,16 @@ (mf/defc color-name {::mf/wrap-props false} - [{:keys [color size on-click on-double-click]}] - (let [{:keys [name color gradient image]} (if (string? color) {:color color :opacity 1} color)] + [{:keys [color size on-click on-double-click origin]}] + (let [{:keys [name color gradient]} (if (string? color) {:color color :opacity 1} color)] (when (or (not size) (> size 64)) [:span {:class (stl/css-case - :color-text (< size 72) - :small-text (and (>= size 64) (< size 72)) - :big-text (>= size 72)) + :color-text (and (= origin :palette) (< size 72)) + :small-text (and (= origin :palette) (>= size 64) (< size 72)) + :big-text (and (= origin :palette) (>= size 72)) + :gradient (some? gradient) + :color-row-name (not= origin :palette)) :title name :on-click on-click :on-double-click on-double-click} - (if (some? image) - (or name (tr "media.image")) - (or name color (uc/gradient-type->string (:type gradient))))]))) + (or name color (uc/gradient-type->string (:type gradient)))]))) diff --git a/frontend/src/app/main/ui/components/color_bullet_new.scss b/frontend/src/app/main/ui/components/color_bullet_new.scss index d6e617251..2dddb14b9 100644 --- a/frontend/src/app/main/ui/components/color_bullet_new.scss +++ b/frontend/src/app/main/ui/components/color_bullet_new.scss @@ -94,3 +94,7 @@ .no-text { display: none; } + +.color-row-name { + color: var(--menu-foreground-color); +} diff --git a/frontend/src/app/main/ui/components/copy_button.scss b/frontend/src/app/main/ui/components/copy_button.scss index c81487f45..ec8e362bb 100644 --- a/frontend/src/app/main/ui/components/copy_button.scss +++ b/frontend/src/app/main/ui/components/copy_button.scss @@ -8,9 +8,8 @@ .copy-button { @include buttonStyle; - @include flexCenter; + width: 100%; height: $s-32; - width: $s-32; border: $s-1 solid transparent; border-radius: $br-8; background-color: transparent; @@ -51,41 +50,32 @@ .copy-wrapper { @include buttonStyle; @include copyWrapperBase; - display: grid; - grid-template-columns: 1fr $s-24; - grid-template-areas: "name button"; width: 100%; height: fit-content; text-align: left; - border: 1px solid transparent; + border: $s-1 solid transparent; .icon-btn { + @include flexCenter; position: absolute; - display: flex; - justify-content: center; - align-items: center; top: 0; right: 0; height: $s-32; - width: $s-32; + width: $s-28; svg { @extend .button-icon-small; + stroke: var(--button-tertiary-foreground-color-focus); display: none; } } &:hover { - .icon-btn { - svg { - display: flex; - stroke: var(--button-tertiary-foreground-color-active); - } + background-color: var(--button-tertiary-background-color-focus); + color: var(--button-tertiary-foreground-color-focus); + border: $s-1 solid var(--button-tertiary-background-color-focus); + .icon-btn svg { + display: flex; } } - &:hover { - background-color: var(--color-background-tertiary); - color: var(--color-foreground-primary); - border: $s-1 solid var(--color-background-tertiary); - } &:focus, &:focus-visible { outline: none; diff --git a/frontend/src/app/main/ui/components/select.cljs b/frontend/src/app/main/ui/components/select.cljs index e3ae25732..ffacb7055 100644 --- a/frontend/src/app/main/ui/components/select.cljs +++ b/frontend/src/app/main/ui/components/select.cljs @@ -97,15 +97,17 @@ current-icon (:icon selected-option) current-icon-ref (i/key->icon current-icon)] [:div {:on-click open-dropdown - :class (dm/str class " " (stl/css-case :custom-select true - :disabled disabled - :icon (some? current-icon-ref)))} + :class (dm/str (stl/css-case :custom-select true + :disabled disabled + :icon (some? current-icon-ref)) + " " class)} (when (and current-icon current-icon-ref) [:span {:class (stl/css :current-icon)} current-icon-ref]) [:span {:class (stl/css :current-label)} current-label] [:span {:class (stl/css :dropdown-button)} i/arrow-refactor] [:& dropdown {:show is-open? :on-close close-dropdown} - [:ul {:ref dropdown-element* :data-direction @dropdown-direction* :class (dm/str dropdown-class " " (stl/css :custom-select-dropdown))} + [:ul {:ref dropdown-element* :data-direction @dropdown-direction* + :class (dm/str (stl/css :custom-select-dropdown) " " dropdown-class)} (for [[index item] (d/enumerate options)] (if (= :separator item) [:li {:class (dom/classnames (stl/css :separator) true) diff --git a/frontend/src/app/main/ui/components/title_bar.cljs b/frontend/src/app/main/ui/components/title_bar.cljs index 0c9899bbc..dcce61678 100644 --- a/frontend/src/app/main/ui/components/title_bar.cljs +++ b/frontend/src/app/main/ui/components/title_bar.cljs @@ -13,7 +13,7 @@ (mf/defc title-bar {::mf/wrap-props false} - [{:keys [collapsable collapsed on-collapsed title children on-btn-click btn-children class all-clickable add-icon-gap]}] + [{:keys [collapsable collapsed on-collapsed title children on-btn-click btn-children class all-clickable add-icon-gap origin]}] (let [klass (dm/str (stl/css :title-bar) " " class)] [:div {:class klass} (if ^boolean collapsable @@ -33,7 +33,10 @@ :on-click on-collapsed} i/arrow-refactor] [:div {:class (stl/css :title)} title]])] - [:div {:class (stl/css-case :title-only true :title-only-icon-gap add-icon-gap)} title]) + [:div {:class (stl/css-case :title-only true + :title-only-icon-gap add-icon-gap + :title-only (not= :inspect origin) + :inspect-title (= :inspect origin))} title]) children (when (some? on-btn-click) [:button {:class (stl/css :title-button) diff --git a/frontend/src/app/main/ui/components/title_bar.scss b/frontend/src/app/main/ui/components/title_bar.scss index e76b9fe2b..bfbd756fc 100644 --- a/frontend/src/app/main/ui/components/title_bar.scss +++ b/frontend/src/app/main/ui/components/title_bar.scss @@ -14,8 +14,39 @@ width: 100%; min-height: $s-32; background-color: var(--title-background-color); +} - .title-wrapper { +.title, +.title-only, +.inspect-title { + @include tabTitleTipography; + display: flex; + align-items: center; + flex-grow: 1; + height: 100%; + min-height: $s-32; + color: var(--title-foreground-color); + overflow: hidden; +} + +.title-only { + margin-left: $s-8; +} + +.inspect-title { + color: var(--title-foreground-color-hover); +} + +.title-wrapper { + display: flex; + align-items: center; + flex-grow: 1; + padding: 0; + color: var(--title-foreground-color); + stroke: var(--title-foreground-color); + overflow: hidden; + .toggle-btn { + @include buttonStyle; display: flex; align-items: center; flex-grow: 1; @@ -23,42 +54,7 @@ color: var(--title-foreground-color); stroke: var(--title-foreground-color); overflow: hidden; - .toggle-btn { - @include buttonStyle; - display: flex; - align-items: center; - flex-grow: 1; - padding: 0; - color: var(--title-foreground-color); - stroke: var(--title-foreground-color); - overflow: hidden; - .collapsabled-icon { - @include flexCenter; - height: $s-24; - border-radius: $br-8; - svg { - @extend .button-icon-small; - transform: rotate(90deg); - stroke: var(--icon-foreground); - } - &.rotated svg { - transform: rotate(0deg); - } - } - &:hover { - color: var(--title-foreground-color-hover); - stroke: var(--title-foreground-color-hover); - .title { - color: var(--title-foreground-color-hover); - stroke: var(--title-foreground-color-hover); - } - .collapsabled-icon svg { - stroke: var(--title-foreground-color-hover); - } - } - } .collapsabled-icon { - @include buttonStyle; @include flexCenter; height: $s-24; border-radius: $br-8; @@ -75,6 +71,7 @@ color: var(--title-foreground-color-hover); stroke: var(--title-foreground-color-hover); .title { + color: var(--title-foreground-color-hover); stroke: var(--title-foreground-color-hover); } .collapsabled-icon svg { @@ -82,17 +79,41 @@ } } } - - .title-button { - @extend .button-tertiary; - height: $s-32; - width: calc($s-24 + $s-4); - padding: 0; + .collapsabled-icon { + @include buttonStyle; + @include flexCenter; + height: $s-24; border-radius: $br-8; svg { - @extend .button-icon; + @extend .button-icon-small; + transform: rotate(90deg); stroke: var(--icon-foreground); } + &.rotated svg { + transform: rotate(0deg); + } + } + &:hover { + color: var(--title-foreground-color-hover); + stroke: var(--title-foreground-color-hover); + .title { + stroke: var(--title-foreground-color-hover); + } + .collapsabled-icon svg { + stroke: var(--title-foreground-color-hover); + } + } +} + +.title-button { + @extend .button-tertiary; + height: $s-32; + width: calc($s-24 + $s-4); + padding: 0; + border-radius: $br-8; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); } } diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes.scss b/frontend/src/app/main/ui/viewer/inspect/attributes.scss index 17a761d01..54980db83 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes.scss @@ -12,4 +12,5 @@ gap: $s-16; width: 100%; height: 100%; + padding-top: $s-8; } diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/blur.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/blur.cljs index 162fb5db8..3b006e94c 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/blur.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/blur.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.viewer.inspect.attributes.blur (:require-macros [app.main.style :as stl]) (:require + [app.common.data.macros :as dm] [app.main.ui.components.copy-button :refer [copy-button]] [app.main.ui.components.title-bar :refer [title-bar]] [app.util.code-gen.style-css :as css] @@ -23,13 +24,16 @@ [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false :title (tr "inspect.attributes.blur") + :origin :inspect :class (stl/css :title-spacing-blur)} (when (= (count shapes) 1) - [:& copy-button {:data (css/get-css-property objects (first shapes) :filter)}])] + [:& copy-button {:data (css/get-css-property objects (first shapes) :filter) + :class (stl/css :copy-btn-title)}])] [:div {:class (stl/css :attributes-content)} (for [shape shapes] - [:div {:class (stl/css :blur-row)} + [:div {:class (stl/css :blur-row) + :key (dm/str "block-" (:id shape) "-blur")} [:div {:class (stl/css :global/attr-label)} "Filter"] [:div {:class (stl/css :global/attr-value)} [:& copy-button {:data (css/get-css-property objects shape :filter)} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/blur.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/blur.scss index e2da40708..a3f2dc334 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/blur.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/blur.scss @@ -21,3 +21,7 @@ .button-children { @extend .copy-button-children; } + +.copy-btn-title { + max-width: $s-28; +} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs index 76001fe46..bbf5148f3 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs @@ -8,6 +8,8 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as cc] + [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.media :as cm] [app.config :as cf] [app.main.refs :as refs] @@ -15,6 +17,7 @@ [app.main.ui.components.color-bullet-new :as cbn] [app.main.ui.components.copy-button :refer [copy-button]] [app.main.ui.components.select :refer [select]] + [app.main.ui.formats :as fmt] [app.util.i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] @@ -43,6 +46,13 @@ (defn- get-file-colors [] (or (mf/deref file-colors-ref) (mf/deref refs/workspace-file-colors))) +(defn get-css-rule-humanized [property] + (as-> property $ + (d/name $) + (str/split $ "-") + (str/join " " $) + (str/capital $))) + (mf/defc color-row [{:keys [color format copy-data on-change-format]}] (let [colors-library (get-colors-library color) file-colors (get-file-colors) @@ -50,85 +60,90 @@ color (assoc color :color-library-name color-library-name) image (:image color)] - [:* - [:div {:class (stl/css :attributes-color-row)} - [:div {:class (stl/css :bullet-wrapper) - :style #js {"--bullet-size" "16px"}} - [:& cbn/color-bullet {:color color - :mini? true}]] - (when-not image - [:div {:class (stl/css :format-wrapper)} - (when-not (and on-change-format (or (:gradient color) image)) - [:div {:class (stl/css :select-format-wrapper)} - [:& select - {:default-value format - :options [{:value :hex :label (tr "inspect.attributes.color.hex")} - {:value :rgba :label (tr "inspect.attributes.color.rgba")} - {:value :hsla :label (tr "inspect.attributes.color.hsla")}] - :on-change on-change-format}]]) - (when (:gradient color) - [:div {:class (stl/css :format-info)} "rgba"])]) + (if image + (let [mtype (-> image :mtype) + name (or (:name image) (tr "media.image")) + extension (cm/mtype->extension mtype)] + [:div {:class (stl/css :attributes-image-as-color-row)} + [:div {:class (stl/css :attributes-color-row)} + [:div {:class (stl/css :bullet-wrapper) + :style #js {"--bullet-size" "16px"}} + [:& cbn/color-bullet {:color color + :mini? true}]] - (if (and copy-data (not image)) - [:& copy-button {:data copy-data - :class (stl/css :color-row-copy-btn)} - [:* - [:div {:class (stl/css :first-row)} - [:div {:class (stl/css :name-opacity)} - [:span {:class (stl/css-case :color-value-wrapper true - :gradient-name (:gradient color))} - (if (:gradient color) - [:& cbn/color-name {:color color :size 80}] - (case format - :hex [:& cbn/color-name {:color color}] - :rgba (let [[r g b a] (cc/hex->rgba (:color color) (:opacity color))] - [:* (str/fmt "%s, %s, %s, %s" r g b a)]) - :hsla (let [[h s l a] (cc/hex->hsla (:color color) (:opacity color)) - result (cc/format-hsla [h s l a])] - [:* result])))] - - (when-not (:gradient color) - [:span {:class (stl/css :opacity-info)} - (str (* 100 (:opacity color)) "%")])]] - - (when color-library-name - [:div {:class (stl/css :second-row)} - [:div {:class (stl/css :color-name-library)} - color-library-name]])]] - - [:div {:class (stl/css :color-info)} - [:div {:class (stl/css :first-row)} - [:div {:class (stl/css :name-opacity)} - [:span {:class (stl/css-case :color-value-wrapper true - :gradient-name (:gradient color))} - (if (:gradient color) - [:& cbn/color-name {:color color}] - (case format - :hex [:& cbn/color-name {:color color - :size 80}] - :rgba (let [[r g b a] (cc/hex->rgba (:color color) (:opacity color))] - [:* (str/fmt "%s, %s, %s, %s" r g b a)]) - :hsla (let [[h s l a] (cc/hex->hsla (:color color) (:opacity color)) - result (cc/format-hsla [h s l a])] - [:* result])))] - - (when-not (:gradient color) + [:div {:class (stl/css :format-wrapper)} + [:div {:class (stl/css :image-format)} + (tr "media.image.short")]] + [:& copy-button {:data copy-data + :class (stl/css :color-row-copy-btn)} + [:div {:class (stl/css-case :color-info true + :two-line (some? color-library-name))} + [:div {:class (stl/css :first-row)} [:span {:class (stl/css :opacity-info)} - (str (* 100 (:opacity color)) "%")])]] + (str (* 100 (:opacity color)) "%")]] - (when color-library-name - [:div {:class (stl/css :second-row)} - [:div {:class (stl/css :color-name-library)} - color-library-name]])])] + (when color-library-name + [:div {:class (stl/css :second-row)} + [:div {:class (stl/css :color-name-library)} + color-library-name]])]] - (when image - (let [mtype (-> image :mtype) - name (or (:name image) (tr "media.image")) - extension (cm/mtype->extension mtype)] - [:a {:class (stl/css :download-button) - :target "_blank" - :download (cond-> name extension (str/concat extension)) - :href (cf/resolve-file-media image)} - (tr "inspect.attributes.image.download")]))])) + [:div {:class (stl/css :image-download)} + [:div {:class (stl/css :image-wrapper)} + [:img {:src (cf/resolve-file-media image)}]] + + [:a {:class (stl/css :download-button) + :target "_blank" + :download (cond-> name extension (str/concat extension)) + :href (cf/resolve-file-media image)} + (tr "inspect.attributes.image.download")]]]]) + + [:div {:class (stl/css :attributes-color-row)} + [:div {:class (stl/css :bullet-wrapper) + :style #js {"--bullet-size" "16px"}} + [:& cbn/color-bullet {:color color + :mini? true}]] + + [:div {:class (stl/css :format-wrapper)} + (when-not (and on-change-format (or (:gradient color) image)) + [:& select + {:default-value format + :class (stl/css :select-format-wrapper) + :options [{:value :hex :label (tr "inspect.attributes.color.hex")} + {:value :rgba :label (tr "inspect.attributes.color.rgba")} + {:value :hsla :label (tr "inspect.attributes.color.hsla")}] + :on-change on-change-format}]) + (when (:gradient color) + [:div {:class (stl/css :format-info)} "rgba"])] + + [:& copy-button {:data copy-data + :class (stl/css-case :color-row-copy-btn true + :one-line (not color-library-name) + :two-line (some? color-library-name))} + [:div {:class (stl/css :first-row)} + [:div {:class (stl/css :name-opacity)} + [:span {:class (stl/css-case :color-value-wrapper true + :gradient-name (:gradient color))} + (if (:gradient color) + [:& cbn/color-name {:color color :size 90}] + (case format + :hex [:& cbn/color-name {:color color}] + :rgba (let [[r g b a] (cc/hex->rgba (:color color) (:opacity color))] + (str/ffmt "%, %, %, %" r g b a)) + :hsla (let [[h s l a] (cc/hex->hsla (:color color) (:opacity color)) + result (cc/format-hsla [h s l a])] + [:* result])))] + + (when-not (:gradient color) + [:span {:class (stl/css :opacity-info)} + (dm/str (-> color + (:opacity) + (d/coalesce 1) + (* 100) + (fmt/format-number)) "%")])]] + + (when color-library-name + [:div {:class (stl/css :second-row)} + [:div {:class (stl/css :color-name-library)} + color-library-name]])]]))) diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/common.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/common.scss index f05e0faa4..7f30931c3 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/common.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/common.scss @@ -6,9 +6,13 @@ @import "refactor/common-refactor.scss"; +.attributes-image-as-color-row { + max-width: $s-240; +} + .attributes-color-row { display: grid; - grid-template-columns: $s-16 $s-72 $s-156; + grid-template-columns: $s-16 $s-72 $s-144; gap: $s-4; } @@ -22,14 +26,19 @@ height: $s-32; } +.image-format { + @include tabTitleTipography; + height: $s-32; + padding: $s-8 0; + color: var(--menu-foreground-color-rest); +} + .select-format-wrapper { width: 100%; - div { - background-color: transparent; - border: none; - padding-left: $s-2; - color: var(--menu-foreground-color-rest); - } + padding: $s-8 $s-2; + background-color: transparent; + border-color: transparent; + color: var(--menu-foreground-color-rest); } .format-info { @@ -43,12 +52,16 @@ color: var(--menu-foreground-color-rest); } +.color-row-copy-btn { + max-width: $s-144; +} + .color-info { display: flex; align-items: flex-start; gap: $s-4; flex-grow: 1; - + max-width: $s-144; button { visibility: hidden; min-width: $s-28; @@ -57,19 +70,22 @@ visibility: visible; } } - -.name-opacity { - display: flex; - align-items: baseline; +.one-line { + max-height: $s-32; +} +.two-line { + display: grid; + grid-template-rows: 1fr 1fr; } - .color-name-wrapper { @include titleTipography; @include flexColumn; padding: $s-8 $s-4 $s-8 $s-8; height: $s-32; max-width: $s-80; + &.gradient-color { + color: var(--menu-foreground-color); max-width: $s-124; } .color-name-library { @@ -92,16 +108,9 @@ padding: $s-8 0; } -.color-info, -.color-row-copy-btn { - display: flex; - max-width: $s-144; -} - .first-row { display: grid; - grid-template-columns: 1fr $s-24; - grid-template-areas: "name button"; + grid-template-columns: 1fr $s-28; height: fit-content; width: 100%; padding: 0; @@ -109,27 +118,26 @@ } .name-opacity { - grid-area: name; height: fit-content; - max-width: $s-124; + width: 100%; line-height: $s-16; + display: grid; + grid-template-columns: 1fr auto; } .color-value-wrapper { + @include textEllipsis; @include inspectValue; text-transform: uppercase; - max-width: $s-80; - padding-right: $s-8; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; &.gradient-name { text-transform: none; } } + .opacity-info { @include inspectValue; text-transform: uppercase; + width: 100%; } .second-row { @@ -146,9 +154,32 @@ color: var(--menu-foreground-color-rest); } +.image-download { + grid-column: 1 / 4; +} + .download-button { @extend .button-secondary; @include tabTitleTipography; height: $s-32; + width: 100%; margin-top: $s-4; } + +.image-wrapper { + background-color: var(--menu-background-color); + position: relative; + @include flexCenter; + width: $s-240; + height: $s-160; + max-height: $s-160; + max-width: $s-248; + margin: $s-8 0; + border-radius: $br-8; + + img { + height: 100%; + width: 100%; + object-fit: contain; + } +} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/fill.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/fill.cljs index 8383ca085..85f607333 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/fill.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/fill.cljs @@ -35,7 +35,6 @@ [{:keys [objects shape]}] (let [format* (mf/use-state :hex) format (deref format*) - color (shape->color shape) on-change (mf/use-fn @@ -55,6 +54,7 @@ (when (seq shapes) [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false + :origin :inspect :title (tr "inspect.attributes.fill") :class (stl/css :title-spacing-fill)}] diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/fill.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/fill.scss index 3f3e3a9bd..9515dad3e 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/fill.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/fill.scss @@ -13,3 +13,8 @@ .title-spacing-fill { @extend .attr-title; } + +.attributes-content { + display: grid; + gap: $s-4; +} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.cljs index 4735502f7..cc7cc70f5 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.cljs @@ -11,6 +11,7 @@ [app.common.data.macros :as dm] [app.main.ui.components.copy-button :refer [copy-button]] [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.viewer.inspect.attributes.common :as cmm] [app.util.code-gen.style-css :as css] [app.util.i18n :refer [tr]] [rumext.v2 :as mf])) @@ -22,12 +23,14 @@ [:* (for [[idx property] (d/enumerate properties)] (when-let [value (css/get-css-value objects shape property)] - [:div {:key (dm/str "block-" idx "-" (d/name property)) - :class (stl/css :geometry-row)} - [:div {:class (stl/css :global/attr-label)} (d/name property)] - [:div {:class (stl/css :global/attr-value)} - [:& copy-button {:data (css/get-css-property objects shape property)} - [:div {:class (stl/css :button-children)} value]]]]))]) + (let [property-name (cmm/get-css-rule-humanized property)] + [:div {:key (dm/str "block-" idx "-" (d/name property)) + :title property-name + :class (stl/css :geometry-row)} + [:div {:class (stl/css :global/attr-label)} property-name] + [:div {:class (stl/css :global/attr-value)} + [:& copy-button {:data (css/get-css-property objects shape property)} + [:div {:class (stl/css :button-children)} value]]]])))]) (mf/defc geometry-panel @@ -35,10 +38,12 @@ [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false :title (tr "inspect.attributes.size") + :origin :inspect :class (stl/css :title-spacing-geometry)} (when (= (count shapes) 1) - [:& copy-button {:data (css/get-shape-properties-css objects (first shapes) properties)}])] + [:& copy-button {:data (css/get-shape-properties-css objects (first shapes) properties) + :class (stl/css :copy-btn-title)}])] (for [shape shapes] [:& geometry-block {:shape shape diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.scss index 2b1f431fb..b32c0c103 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/geometry.scss @@ -21,3 +21,7 @@ .button-children { @extend .copy-button-children; } + +.copy-btn-title { + max-width: $s-28; +} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/image.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/image.cljs index 4f22213db..093b6a657 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/image.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/image.cljs @@ -23,7 +23,7 @@ [{:keys [objects shapes]}] (for [shape (filter cfh/image-shape? shapes)] [:div {:class (stl/css :attributes-block) - :key (str "image-" (:id shape))} + :key (str "image-" (:id shape))} [:div {:class (stl/css :image-wrapper)} [:img {:src (cf/resolve-file-media (-> shape :metadata))}]] diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/layout.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/layout.cljs index e015aecd1..ecfb19e3b 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/layout.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/layout.cljs @@ -8,9 +8,11 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.types.shape.layout :as ctl] [app.main.ui.components.copy-button :refer [copy-button]] [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.viewer.inspect.attributes.common :as cmm] [app.util.code-gen.style-css :as css] [rumext.v2 :as mf])) @@ -31,13 +33,16 @@ [{:keys [objects shape]}] (for [property properties] (when-let [value (css/get-css-value objects shape property)] - [:div {:class (stl/css :layout-row)} - [:div {:title (d/name property) - :class (stl/css :global/attr-label)} (d/name property)] - [:div {:class (stl/css :global/attr-value)} + (let [property-name (cmm/get-css-rule-humanized property)] + [:div {:class (stl/css :layout-row)} + [:div {:title property-name + :key (dm/str "layout-" (:id shape) "-" (d/name property)) + :class (stl/css :global/attr-label)} + property-name] + [:div {:class (stl/css :global/attr-value)} - [:& copy-button {:data (css/get-css-property objects shape property)} - [:div {:class (stl/css :button-children)} value]]]]))) + [:& copy-button {:data (css/get-css-property objects shape property)} + [:div {:class (stl/css :button-children)} value]]]])))) (mf/defc layout-panel [{:keys [objects shapes]}] @@ -46,11 +51,13 @@ (when (seq shapes) [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false + :origin :inspect :title "Layout" :class (stl/css :title-spacing-layout)} (when (= (count shapes) 1) - [:& copy-button {:data (css/get-shape-properties-css objects (first shapes) properties)}])] + [:& copy-button {:data (css/get-shape-properties-css objects (first shapes) properties) + :class (stl/css :copy-btn-title)}])] (for [shape shapes] [:& layout-block {:shape shape diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/layout.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/layout.scss index e2a409c0f..8a84e1d98 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/layout.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/layout.scss @@ -21,3 +21,7 @@ .button-children { @extend .copy-button-children; } + +.copy-btn-title { + max-width: $s-28; +} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.cljs index 14eaf7f93..4ba5a98a6 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.cljs @@ -8,9 +8,11 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.types.shape.layout :as ctl] [app.main.ui.components.copy-button :refer [copy-button]] [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.viewer.inspect.attributes.common :as cmm] [app.util.code-gen.style-css :as css] [rumext.v2 :as mf])) @@ -33,12 +35,14 @@ [{:keys [objects shape]}] (for [property properties] (when-let [value (css/get-css-value objects shape property)] - [:div {:class (stl/css :layout-element-row)} - [:div {:class (stl/css :global/attr-label)} (d/name property)] - [:div {:class (stl/css :global/attr-value)} + (let [property-name (cmm/get-css-rule-humanized property)] + [:div {:class (stl/css :layout-element-row) + :key (dm/str "layout-element-" (:id shape) "-" (d/name property))} + [:div {:class (stl/css :global/attr-label)} property-name] + [:div {:class (stl/css :global/attr-value)} - [:& copy-button {:data (css/get-css-property objects shape property)} - [:div {:class (stl/css :button-children)} value]]]]))) + [:& copy-button {:data (css/get-css-property objects shape property)} + [:div {:class (stl/css :button-children)} value]]]])))) (mf/defc layout-element-panel [{:keys [objects shapes]}] @@ -67,7 +71,8 @@ :title menu-title :class (stl/css :title-spacing-layout-element)} (when (= (count shapes) 1) - [:& copy-button {:data (css/get-shape-properties-css objects (first shapes) properties)}])] + [:& copy-button {:data (css/get-shape-properties-css objects (first shapes) properties) + :class (stl/css :copy-btn-title)}])] (for [shape shapes] [:& layout-element-block {:shape shape diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.scss index 6ef7e6cea..56b174dd5 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/layout_element.scss @@ -21,3 +21,7 @@ .button-children { @extend .copy-button-children; } + +.copy-btn-title { + max-width: $s-28; +} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/shadow.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/shadow.cljs index 586d4488a..c77ab51b3 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/shadow.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/shadow.cljs @@ -54,6 +54,7 @@ (when (and (seq shapes) (> (count shapes) 0)) [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false + :origin :inspect :title (tr "inspect.attributes.shadow") :class (stl/css :title-spacing-shadow)}] @@ -61,4 +62,5 @@ (for [shape shapes] (for [shadow (:shadow shape)] [:& shadow-block {:shape shape + :key (dm/str "block-" (:id shape) "-shadow") :shadow shadow}]))]]))) diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.cljs index 9dd86a035..2ba125be3 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.cljs @@ -62,6 +62,7 @@ (when (seq shapes) [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false + :origin :inspect :title (tr "inspect.attributes.stroke") :class (stl/css :title-spacing-stroke)}] diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.scss index 86cb67104..fe0f59df4 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/stroke.scss @@ -25,3 +25,8 @@ .button-children { @extend .copy-button-children; } + +.attributes-content { + display: grid; + gap: $s-4; +} diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/svg.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/svg.cljs index 8df36110f..c788c95db 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/svg.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/svg.cljs @@ -27,19 +27,25 @@ [:& copy-button {:data (map->css value)}]] (for [[attr-key attr-value] value] - [:& svg-attr {:attr attr-key :value attr-value}])] + [:& svg-attr {:attr attr-key :value attr-value :key (str/join "svg-key-" attr-key)}])] - [:div {:class (stl/css :svg-row)} - [:div {:class (stl/css :global/attr-label)} (d/name attr)] - [:div {:class (stl/css :global/attr-value)} - [:& copy-button {:data (d/name value)} - [:div {:class (stl/css :button-children)} (str value)]]]])) + (let [attr-name (as-> attr $ + (d/name $) + (str/split $ "-") + (str/join " " $) + (str/capital $))] + [:div {:class (stl/css :svg-row)} + [:div {:class (stl/css :global/attr-label)} attr-name] + [:div {:class (stl/css :global/attr-value)} + [:& copy-button {:data (d/name value) + :class (stl/css :copy-btn-title)} + [:div {:class (stl/css :button-children)} (str value)]]]]))) (mf/defc svg-block [{:keys [shape]}] [:* (for [[attr-key attr-value] (:svg-attrs shape)] - [:& svg-attr {:attr attr-key :value attr-value}])]) + [:& svg-attr {:attr attr-key :value attr-value :key (str/join "svg-block-key" attr-key)}])]) (mf/defc svg-panel @@ -48,6 +54,7 @@ (when (seq (:svg-attrs shape)) [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false + :origin :inspect :title (tr "workspace.sidebar.options.svg-attrs.title") :class (stl/css :title-spacing-svg)}] [:& svg-block {:shape shape}]]))) diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/text.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/text.cljs index f3f817397..137fcc01c 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/text.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/text.cljs @@ -99,7 +99,7 @@ [:div {:class (stl/css :global/attr-value)} [:& copy-button {:data (copy-style-data style :font-style)} [:div {:class (stl/css :button-children)} - (str (:font-style style))]]]]) + (dm/str (:font-style style))]]]]) (when (:font-size style) [:div {:class (stl/css :text-row)} @@ -117,7 +117,7 @@ [:div {:class (stl/css :global/attr-value)} [:& copy-button {:data (copy-style-data style :font-weight)} [:div {:class (stl/css :button-children)} - (str (:font-weight style))]]]]) + (dm/str (:font-weight style))]]]]) (when (:line-height style) [:div {:class (stl/css :text-row)} @@ -191,9 +191,10 @@ (when-let [shapes (seq (filter has-text? shapes))] [:div {:class (stl/css :attributes-block)} [:& title-bar {:collapsable false + :origin :inspect :title (tr "inspect.attributes.typography") :class (stl/css :title-spacing-text)}] (for [shape shapes] [:& text-block {:shape shape - :key (str "text-block" (:id shape))}])])) + :key (dm/str "text-block" (:id shape))}])])) diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/text.scss b/frontend/src/app/main/ui/viewer/inspect/attributes/text.scss index a506af1b4..d32a5a516 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/text.scss +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/text.scss @@ -30,7 +30,7 @@ } .attributes-content-row { - max-width: $s-252; + max-width: $s-240; min-height: calc($s-2 + $s-32); border-radius: $br-8; border: $s-1 solid var(--menu-border-color-disabled); diff --git a/frontend/src/app/main/ui/viewer/inspect/code.cljs b/frontend/src/app/main/ui/viewer/inspect/code.cljs index 03afee4ac..6baa45ef9 100644 --- a/frontend/src/app/main/ui/viewer/inspect/code.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/code.cljs @@ -19,7 +19,7 @@ [app.main.store :as st] [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.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.hooks :as hooks] [app.main.ui.hooks.resize :refer [use-resize-hook]] [app.main.ui.icons :as i] @@ -177,10 +177,10 @@ style-size :size} (use-resize-hook :code 400 100 800 :y false :bottom) - set-style - (mf/use-callback - (fn [value] - (reset! style-type* value))) + ;; set-style + ;; (mf/use-callback + ;; (fn [value] + ;; (reset! style-type* value))) set-markup (mf/use-callback @@ -251,10 +251,13 @@ :rotated collapsed-css?)} i/arrow-refactor]] - [:& select {:default-value style-type - :class (stl/css :code-lang-select) - :on-change set-style - :options [{:label "CSS" :value "css"}]}] + [:div {:class (stl/css :code-lang-option)} + "CSS"] + ;; We will have a select when we have more than one option + ;; [:& 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) @@ -262,6 +265,7 @@ i/code-refactor] [:& copy-button {:data #(replace-map style-code images-data) + :class (stl/css :css-copy-btn) :on-copied on-style-copied}]]] (when-not collapsed-css? @@ -285,11 +289,16 @@ :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}] + + [:& radio-buttons {:selected markup-type + :on-change set-markup + :class (stl/css :code-lang-options) + :wide true + :name "listing-style"} + [:& radio-button {:value "html" + :id :html}] + [:& radio-button {:value "svg" + :id :svg}]] [:div {:class (stl/css :action-btns)} [:button {:class (stl/css :expand-button) @@ -297,6 +306,7 @@ i/code-refactor] [:& copy-button {:data #(replace-map markup-code images-data) + :class (stl/css :html-copy-btn) :on-copied on-markup-copied}]]] (when-not collapsed-markup? diff --git a/frontend/src/app/main/ui/viewer/inspect/code.scss b/frontend/src/app/main/ui/viewer/inspect/code.scss index 5b6d66c9c..a383684c7 100644 --- a/frontend/src/app/main/ui/viewer/inspect/code.scss +++ b/frontend/src/app/main/ui/viewer/inspect/code.scss @@ -48,8 +48,8 @@ } .code-row-lang { - display: flex; - justify-content: space-between; + display: grid; + grid-template-columns: $s-12 1fr $s-60; gap: $s-4; width: 100%; } @@ -61,13 +61,14 @@ } .action-btns { - display: flex; + display: grid; + grid-template-columns: 1fr 1fr; gap: $s-4; - flex: 1; - justify-content: end; } -.expand-button { +.expand-button, +.css-copy-btn, +.html-copy-btn { @extend .button-tertiary; height: $s-32; width: $s-28; @@ -77,6 +78,9 @@ } } +.code-lang-options { + max-width: $s-108; +} .code-lang-select { @include tabTitleTipography; width: $s-72; @@ -84,6 +88,13 @@ background-color: transparent; color: var(--menu-foreground-color-disabled); } +.code-lang-option { + @include tabTitleTipography; + width: $s-72; + height: $s-32; + padding: $s-8; + color: var(--menu-foreground-color-disabled); +} .code-row-display { flex: 1; 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 b66e44ce7..5d9646ab6 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss @@ -14,8 +14,6 @@ left: unset; right: unset; grid-area: right-sidebar; - padding-top: $s-8; - padding-left: $s-12; overflow: hidden; &.viewer-code { height: calc(100vh - $s-48); @@ -26,18 +24,20 @@ height: 100%; display: flex; flex-direction: column; + gap: $s-8; } .shape-row { display: flex; gap: $s-8; align-items: center; - margin-bottom: $s-16; + height: $s-32; } .layers-icon, .shape-icon { @include flexCenter; + height: $s-32; svg { @extend .button-icon-small; stroke: var(--icon-foreground); @@ -46,7 +46,9 @@ .layer-title { @include titleTipography; - color: $df-primary; + height: $s-32; + padding: $s-8 0; + color: var(--assets-item-name-foreground-color-rest); } .empty { diff --git a/frontend/src/app/main/ui/workspace/color_palette.cljs b/frontend/src/app/main/ui/workspace/color_palette.cljs index ceaeebd9b..b07848671 100644 --- a/frontend/src/app/main/ui/workspace/color_palette.cljs +++ b/frontend/src/app/main/ui/workspace/color_palette.cljs @@ -31,7 +31,7 @@ :title (uc/get-color-name color) :on-click select-color} [:& cb/color-bullet {:color color}] - [:& cb/color-name {:color color :size size}]])) + [:& cb/color-name {:color color :size size :origin :palette}]])) (mf/defc palette diff --git a/frontend/src/app/main/ui/workspace/sidebar.scss b/frontend/src/app/main/ui/workspace/sidebar.scss index b2ece935e..b14ca1253 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.scss +++ b/frontend/src/app/main/ui/workspace/sidebar.scss @@ -16,7 +16,6 @@ $width-settings-bar-max: $s-500; "content resize"; grid-template-rows: $s-52 1fr; grid-template-columns: 1fr 0; - gap: $s-8 0; position: relative; grid-area: left-sidebar; min-width: $width-settings-bar; @@ -85,10 +84,10 @@ $width-settings-bar-max: $s-500; .resize-area-horiz { position: absolute; - top: calc($s-80 + var(--height, 200px)); + // top: calc($s-88 + var(--height, 200px)); left: 0; width: 100%; - height: $s-12; - border-top: $s-2 solid var(--resize-area-border-color); + // height: $s-8; + border-bottom: $s-2 solid var(--resize-area-border-color); cursor: ns-resize; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.scss b/frontend/src/app/main/ui/workspace/sidebar/layers.scss index 4b39fbaa4..25cf2cc4a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.scss @@ -241,8 +241,7 @@ } .tool-window-content { - // TODO: sass variables are not being interpolated here, find why - --calculated-height: calc(128px + var(--height, 200px)); + --calculated-height: calc(#{$s-136} + var(--height, #{$s-200})); display: flex; flex-direction: column; height: calc(100vh - var(--calculated-height)); diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 46f2e63c1..f26593180 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5056,6 +5056,9 @@ msgstr "Done" msgid "media.image" msgstr "Image" +msgid "media.image.short" +msgstr "img" + msgid "media.solid" msgstr "Solid" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 8c8c0d4cc..4fe0c535e 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5140,6 +5140,9 @@ msgstr "Hecho" msgid "media.image" msgstr "Imagen" +msgid "media.image.short" +msgstr "img" + msgid "media.solid" msgstr "Sólido" From 377d9682da629b8b73929081b17579c910810edd Mon Sep 17 00:00:00 2001 From: Alejandro Alonso <alejandroalonsofernandez@gmail.com> Date: Tue, 13 Feb 2024 16:49:45 +0100 Subject: [PATCH 22/23] :bug: Fix default constraints for migrated graphics --- backend/src/app/features/components_v2.clj | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/backend/src/app/features/components_v2.clj b/backend/src/app/features/components_v2.clj index 72f416bdf..67cf48b07 100644 --- a/backend/src/app/features/components_v2.clj +++ b/backend/src/app/features/components_v2.clj @@ -1187,15 +1187,18 @@ "Convert a media object that contains a bitmap image into shapes, one shape of type :image and one group that contains it." [{:keys [name width height id mtype]} frame-id position] - (let [frame-shape (cts/setup-shape - {:type :frame - :x (:x position) - :y (:y position) - :width width - :height height - :name name - :frame-id frame-id - :parent-id frame-id}) + (let [frame-shape (-> (cts/setup-shape + {:type :frame + :x (:x position) + :y (:y position) + :width width + :height height + :name name + :frame-id frame-id + :parent-id frame-id}) + (assoc + :proportion (/ width height) + :proportion-lock true)) img-shape (cts/setup-shape {:type :image @@ -1209,7 +1212,9 @@ :mtype mtype} :name name :frame-id (:id frame-shape) - :parent-id (:id frame-shape)})] + :parent-id (:id frame-shape) + :constraints-h :scale + :constraints-v :scale})] [frame-shape [img-shape]])) (defn- parse-datauri From ee8cdfc7d34daf0d965861fa0407f83e3d31e34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com> Date: Wed, 14 Feb 2024 11:37:05 +0100 Subject: [PATCH 23/23] :bug: Fix boolean flatten icon size --- .../workspace/sidebar/options/menus/bool.cljs | 7 +++-- .../workspace/sidebar/options/menus/bool.scss | 26 +++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) 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 7a25e1bf5..c2baaf769 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 @@ -17,6 +17,9 @@ [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) +(def ^:private flatten-icon + (i/icon-xref :boolean-flatten-refactor (stl/css :flatten-icon))) + (mf/defc bool-options [] (let [selected (mf/deref refs/selected-objects) @@ -86,9 +89,9 @@ [:button {:title (tr "workspace.shape.menu.flatten") :class (stl/css-case - :flatten true + :flatten-button true :disabled disabled-flatten) :disabled disabled-flatten :on-click flatten-objects} - i/boolean-flatten-refactor]]]))) + flatten-icon]]]))) 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 625a80b71..bc26d5b8b 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 @@ -18,29 +18,29 @@ align-items: center; } -.flatten { +.flatten-button { @extend .button-tertiary; - height: $s-28; - width: $s-28; + height: $s-32; + width: $s-32; border-radius: $br-8; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } + --flatten-icon-foreground-color: var(--icon-foreground); + &.disabled { cursor: default; - svg { - stroke: var(--button-foreground-color-disabled); - } + --flatten-icon-foreground-color: var(--button-foreground-color-disabled); + &:hover { background-color: var(--panel-background-color); - svg { - stroke: var(--button-foreground-color-disabled); - } + --flatten-icon-foreground-color: var(--button-foreground-color-disabled); } } } +.flatten-icon { + @extend .button-icon; + stroke: var(--flatten-icon-foreground-color); +} + .boolean-radio-btn { background-color: transparent; }