Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2024-10-15 09:30:03 +02:00
commit c841ed6419
22 changed files with 173 additions and 160 deletions

View file

@ -42,6 +42,7 @@
### :bug: Bugs fixed ### :bug: Bugs fixed
- Fix problem with constraints buttons [Taiga #8465](https://tree.taiga.io/project/penpot/issue/8465)
- Fix problem with go back button on error page [Taiga #8887](https://tree.taiga.io/project/penpot/issue/8887) - Fix problem with go back button on error page [Taiga #8887](https://tree.taiga.io/project/penpot/issue/8887)
- Fix problem with shadows in text for Safari [Taiga #8770](https://tree.taiga.io/project/penpot/issue/8770) - Fix problem with shadows in text for Safari [Taiga #8770](https://tree.taiga.io/project/penpot/issue/8770)
- Fix a regression with feedback form subject and content limits [Taiga #8908](https://tree.taiga.io/project/penpot/issue/8908) - Fix a regression with feedback form subject and content limits [Taiga #8908](https://tree.taiga.io/project/penpot/issue/8908)
@ -50,6 +51,15 @@
- Fix problem with precision on boolean calculation [Taiga #8482](https://tree.taiga.io/project/penpot/issue/8482) - Fix problem with precision on boolean calculation [Taiga #8482](https://tree.taiga.io/project/penpot/issue/8482)
- Fix problem when translating multiple path points [Github #4459](https://github.com/penpot/penpot/issues/4459) - Fix problem when translating multiple path points [Github #4459](https://github.com/penpot/penpot/issues/4459)
- Fix problem on importing (and exporting) files with flows [Taiga #8914](https://tree.taiga.io/project/penpot/issue/8914) - Fix problem on importing (and exporting) files with flows [Taiga #8914](https://tree.taiga.io/project/penpot/issue/8914)
- Fix Internal Error page: "go to your penpot" wrong design [Taiga #8922](https://tree.taiga.io/project/penpot/issue/8922)
- Fix problem updating layout when toggle visibility in component copy [Github #5143](https://github.com/penpot/penpot/issues/5143)
- Fix "Done" button on toolbar on inspect mode should go to design mode [Taiga #8933](https://tree.taiga.io/project/penpot/issue/8933)
- Fix problem with shortcuts in text editor [Github #5078](https://github.com/penpot/penpot/issues/5078)
- Fix problems with show in viewer and interactions [Github #4868](https://github.com/penpot/penpot/issues/4868)
- Add visual feedback when moving an element into a board [Github #3210](https://github.com/penpot/penpot/issues/3210)
- Fix percent calculation on grid layout tracks [Github #4688](https://github.com/penpot/penpot/issues/4688)
- Fix problem with caps and inner shadows [Github #4517](https://github.com/penpot/penpot/issues/4517)
- Fix problem with horizontal/vertical lines and shadows [Github #4516](https://github.com/penpot/penpot/issues/4516)
## 2.2.1 ## 2.2.1

View file

@ -135,7 +135,7 @@
(l/dbg :hint "run webhook" (l/dbg :hint "run webhook"
:event-name (:name event) :event-name (:name event)
:webhook-id (:id whook) :webhook-id (str (:id whook))
:webhook-uri (:uri whook) :webhook-uri (:uri whook)
:webhook-mtype (:mtype whook)) :webhook-mtype (:mtype whook))

View file

@ -328,8 +328,10 @@
:page-name page-name :page-name page-name
:position position :position position
:content content :content content
:frame-id frame-id}] :frame-id frame-id}
(db/tx-run! cfg create-comment-thread params)))) thread (db/tx-run! cfg create-comment-thread params)]
(vary-meta thread assoc ::audit/props thread))))
(defn- create-comment-thread (defn- create-comment-thread
[{:keys [::db/conn] :as cfg} [{:keys [::db/conn] :as cfg}

View file

@ -60,6 +60,7 @@
filter-y (mth/min y (+ y offset-y (- spread) (- blur) -5)) filter-y (mth/min y (+ y offset-y (- spread) (- blur) -5))
filter-w (+ w (mth/abs offset-x) (* spread 2) (* blur 2) 10) filter-w (+ w (mth/abs offset-x) (* spread 2) (* blur 2) 10)
filter-h (+ h (mth/abs offset-y) (* spread 2) (* blur 2) 10)] filter-h (+ h (mth/abs offset-y) (* spread 2) (* blur 2) 10)]
(grc/make-rect filter-x filter-y filter-w filter-h))) (grc/make-rect filter-x filter-y filter-w filter-h)))
(defn get-rect-filter-bounds (defn get-rect-filter-bounds
@ -101,7 +102,7 @@
(map #(case (get % :stroke-alignment :center) (map #(case (get % :stroke-alignment :center)
:center (/ (:stroke-width % 0) 2) :center (/ (:stroke-width % 0) 2)
:outer (:stroke-width % 0) :outer (:stroke-width % 0)
0)) (:stroke-width % 0)))
(reduce d/max 0)) (reduce d/max 0))
stroke-margin stroke-margin

View file

@ -124,7 +124,7 @@
;; All parents of any deleted shape must be resized. ;; All parents of any deleted shape must be resized.
(into res (cfh/get-parent-ids objects id))) (into res (cfh/get-parent-ids objects id)))
(d/ordered-set) (d/ordered-set)
ids-to-delete) (concat ids-to-delete ids-to-hide))
all-children all-children
(->> ids-to-delete ;; Children of deleted shapes must be also deleted. (->> ids-to-delete ;; Children of deleted shapes must be also deleted.
@ -408,17 +408,12 @@
;; Resize parent containers that need to ;; Resize parent containers that need to
(pcb/resize-parents parents)))) (pcb/resize-parents parents))))
(defn change-show-in-viewer [shape hide?] (defn change-show-in-viewer [shape hide?]
(cond-> (assoc shape :hide-in-viewer hide?) (assoc shape :hide-in-viewer hide?))
;; When a frame is no longer shown in view mode, it cannot have interactions
hide?
(dissoc :interactions)))
(defn add-new-interaction [shape interaction] (defn add-new-interaction [shape interaction]
(-> shape (-> shape
(update :interactions ctsi/add-interaction interaction) (update :interactions ctsi/add-interaction interaction)))
;; When a interaction is created, the frame must be shown in view mode
(dissoc :hide-in-viewer))) (defn show-in-viewer [shape]
(dissoc shape :hide-in-viewer))

View file

@ -1,75 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns common-tests.logic.hide-in-viewer-test
(:require
[app.common.files.changes-builder :as pcb]
[app.common.logic.shapes :as cls]
[app.common.test-helpers.compositions :as tho]
[app.common.test-helpers.files :as thf]
[app.common.test-helpers.ids-map :as thi]
[app.common.test-helpers.shapes :as ths]
[app.common.types.shape.interactions :as ctsi]
[clojure.test :as t]))
(t/use-fixtures :each thi/test-fixture)
(t/deftest test-remove-show-in-view-mode-delete-interactions
(let [;; ==== Setup
file (-> (thf/sample-file :file1)
(tho/add-frame :frame-dest)
(tho/add-frame :frame-origin)
(ths/add-interaction :frame-origin :frame-dest))
frame-origin (ths/get-shape file :frame-origin)
page (thf/current-page file)
;; ==== Action
changes (-> (pcb/empty-changes nil (:id page))
(pcb/with-objects (:objects page))
(pcb/update-shapes [(:id frame-origin)] #(cls/change-show-in-viewer % true)))
file' (thf/apply-changes file changes)
;; ==== Get
frame-origin' (ths/get-shape file' :frame-origin)]
;; ==== Check
(t/is (some? (:interactions frame-origin)))
(t/is (nil? (:interactions frame-origin')))))
(t/deftest test-add-new-interaction-updates-show-in-view-mode
(let [;; ==== Setup
file (-> (thf/sample-file :file1)
(tho/add-frame :frame-dest :hide-in-viewer true)
(tho/add-frame :frame-origin :hide-in-viewer true))
frame-dest (ths/get-shape file :frame-dest)
frame-origin (ths/get-shape file :frame-origin)
page (thf/current-page file)
;; ==== Action
new-interaction (-> ctsi/default-interaction
(ctsi/set-destination (:id frame-dest))
(assoc :position-relative-to (:id frame-dest)))
changes (-> (pcb/empty-changes nil (:id page))
(pcb/with-objects (:objects page))
(pcb/update-shapes [(:id frame-origin)] #(cls/add-new-interaction % new-interaction)))
file' (thf/apply-changes file changes)
;; ==== Get
frame-origin' (ths/get-shape file' :frame-origin)]
;; ==== Check
(t/is (true? (:hide-in-viewer frame-origin)))
(t/is (nil? (:hide-in-viewer frame-origin')))))

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
export PATH=/usr/lib/jvm/openjdk/bin:/usr/local/nodejs/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin export PATH=/usr/lib/jvm/openjdk/bin:/usr/local/nodejs/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
export JAVA_OPTS="-Xmx1000m -Xms50m" export JAVA_OPTS=${JAVA_OPTS:-"-Xmx1000m -Xms200m"};
alias l='ls --color -GFlh' alias l='ls --color -GFlh'
alias rm='rm -r' alias rm='rm -r'

View file

@ -10,7 +10,7 @@ rm -rf target
export NODE_ENV=production; export NODE_ENV=production;
# Build the application # Build the application
clojure -J-Xms100M -J-Xmx1000M -J-XX:+UseSerialGC -M:dev:shadow-cljs release main; clojure -M:dev:shadow-cljs release main;
# Remove source # Remove source
rm -rf target/app; rm -rf target/app;

View file

@ -111,6 +111,7 @@
(def flex-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/")) (def flex-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/"))
(def grid-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/")) (def grid-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/"))
(def plugins-list-uri (obj/get global "penpotPluginsListUri" "https://penpot-docs-plugins.pages.dev/plugins/getting-started/#examples")) (def plugins-list-uri (obj/get global "penpotPluginsListUri" "https://penpot-docs-plugins.pages.dev/plugins/getting-started/#examples"))
(def plugins-whitelist (into #{} (obj/get global "penpotPluginsWhitelist" [])))
(defn- normalize-uri (defn- normalize-uri
[uri-str] [uri-str]

View file

@ -24,6 +24,10 @@ target.stopCallback = function (e, element, combo) {
return false return false
} }
if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) {
return false;
}
if ('composedPath' in e && typeof e.composedPath === 'function') { if ('composedPath' in e && typeof e.composedPath === 'function') {
// For open shadow trees, update `element` so that the following check works. // For open shadow trees, update `element` so that the following check works.
const initialEventTarget = e.composedPath()[0]; const initialEventTarget = e.composedPath()[0];

View file

@ -147,11 +147,15 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [page-id (or page-id (:current-page-id state))] (let [page-id (or page-id (:current-page-id state))]
(rx/of (dwsh/update-shapes (rx/of (dwsh/update-shapes [shape-id]
[shape-id] (fn [shape]
(fn [shape] (cls/add-new-interaction shape interaction))
(cls/add-new-interaction shape interaction)) {:page-id page-id})
{:page-id page-id}))))))
(when (:destination interaction)
(dwsh/update-shapes [(:destination interaction)]
cls/show-in-viewer
{:page-id page-id})))))))
(defn add-new-interaction (defn add-new-interaction
([shape] (add-new-interaction shape nil)) ([shape] (add-new-interaction shape nil))
@ -167,15 +171,20 @@
flows (get page :objects) flows (get page :objects)
flow (ctp/get-frame-flow flows (:id frame))] flow (ctp/get-frame-flow flows (:id frame))]
(rx/concat (rx/concat
(rx/of (dwsh/update-shapes [(:id shape)] (rx/of (dwsh/update-shapes
(fn [shape] [(:id shape)]
(let [new-interaction (-> ctsi/default-interaction (fn [shape]
(ctsi/set-destination destination) (let [new-interaction (-> ctsi/default-interaction
(assoc :position-relative-to (:id shape)))] (ctsi/set-destination destination)
(cls/add-new-interaction shape new-interaction))))) (assoc :position-relative-to (:id shape)))]
(when (and (not (connected-frame? objects (:id frame))) (cls/add-new-interaction shape new-interaction))))
(nil? flow))
(rx/of (add-flow (:id frame)))))))))) (when destination
(dwsh/update-shapes [destination] cls/show-in-viewer))
(when (and (not (connected-frame? objects (:id frame)))
(nil? flow))
(add-flow (:id frame))))))))))
(defn remove-interaction (defn remove-interaction
([shape index] ([shape index]
@ -186,8 +195,7 @@
(watch [_ _ _] (watch [_ _ _]
(rx/of (dwsh/update-shapes [(:id shape)] (rx/of (dwsh/update-shapes [(:id shape)]
(fn [shape] (fn [shape]
(update shape :interactions (update shape :interactions ctsi/remove-interaction index))
ctsi/remove-interaction index))
{:page-id page-id})))))) {:page-id page-id}))))))
(defn update-interaction (defn update-interaction
([shape index update-fn] ([shape index update-fn]
@ -196,11 +204,16 @@
(ptk/reify ::update-interaction (ptk/reify ::update-interaction
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(rx/of (dwsh/update-shapes [(:id shape)] (let [interactions (ctsi/update-interaction (:interactions shape) index update-fn)
(fn [shape] interaction (nth interactions index)]
(update shape :interactions (rx/of (dwsh/update-shapes
ctsi/update-interaction index update-fn)) [(:id shape)]
options)))))) (fn [shape]
(assoc shape :interactions interactions))
options)
(when (some? (:destination interaction))
(dwsh/update-shapes [(:destination interaction)] cls/show-in-viewer options))))))))
(defn remove-all-interactions-nav-to (defn remove-all-interactions-nav-to
"Remove all interactions that navigate to the given frame." "Remove all interactions that navigate to the given frame."

View file

@ -10,6 +10,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.shapes.bounds :as gsb] [app.common.geom.shapes.bounds :as gsb]
[app.common.math :as mth]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -129,6 +130,34 @@
[filters] [filters]
(map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters)))) (map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters))))
(defn filter-coords
[bounds selrect padding]
(if (or (mth/close? 0.01 (:width selrect))
(mth/close? 0.01 (:height selrect)))
;; We cannot use "objectBoundingbox" if the shape doesn't have width/heigth
;; From the SVG spec (https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
;; Keyword objectBoundingBox should not be used when the geometry of the applicable element
;; has no width or no height, such as the case of a horizontal or vertical line, even when
;; the line has actual thickness when viewed due to having a non-zero stroke width since
;; stroke width is ignored for bounding box calculations. When the geometry of the
;; applicable element has no width or height and objectBoundingBox is specified, then
;; the given effect (e.g., a gradient or a filter) will be ignored.
(let [filter-width (+ (:width bounds) (* 2 (:horizontal padding)))
filter-height (+ (:height bounds) (* 2 (:vertical padding)))
filter-x (- (:x bounds) #_(:x selrect) (:horizontal padding))
filter-y (- (:y bounds) #_(:y selrect) (:vertical padding))
filter-units "userSpaceOnUse"]
[filter-x filter-y filter-width filter-height filter-units])
;; If the width/height is not zero we use objectBoundingBox as it's more stable
(let [filter-width (/ (+ (:width bounds) (* 2 (:horizontal padding))) (:width selrect))
filter-height (/ (+ (:height bounds) (* 2 (:vertical padding))) (:height selrect))
filter-x (/ (- (:x bounds) (:x selrect) (:horizontal padding)) (:width selrect))
filter-y (/ (- (:y bounds) (:y selrect) (:vertical padding)) (:height selrect))
filter-units "objectBoundingBox"]
[filter-x filter-y filter-width filter-height filter-units])))
(mf/defc filters (mf/defc filters
[{:keys [filter-id shape]}] [{:keys [filter-id shape]}]
@ -136,17 +165,17 @@
bounds (gsb/get-rect-filter-bounds (:selrect shape) filters (or (-> shape :blur :value) 0)) bounds (gsb/get-rect-filter-bounds (:selrect shape) filters (or (-> shape :blur :value) 0))
padding (gsb/calculate-padding shape) padding (gsb/calculate-padding shape)
selrect (:selrect shape) selrect (:selrect shape)
filter-x (/ (- (:x bounds) (:x selrect) (:horizontal padding)) (:width selrect))
filter-y (/ (- (:y bounds) (:y selrect) (:vertical padding)) (:height selrect)) [filter-x filter-y filter-width filter-height filter-units]
filter-width (/ (+ (:width bounds) (* 2 (:horizontal padding))) (:width selrect)) (filter-coords bounds selrect padding)]
filter-height (/ (+ (:height bounds) (* 2 (:vertical padding))) (:height selrect))]
(when (> (count filters) 2) (when (> (count filters) 2)
[:filter {:id filter-id [:filter {:id filter-id
:x filter-x :x filter-x
:y filter-y :y filter-y
:width filter-width :width filter-width
:height filter-height :height filter-height
:filterUnits "objectBoundingBox" :filterUnits filter-units
:color-interpolation-filters "sRGB"} :color-interpolation-filters "sRGB"}
(for [[index entry] (d/enumerate filters)] (for [[index entry] (d/enumerate filters)]
[:& filter-entry {:key (dm/str filter-id "-" index) [:& filter-entry {:key (dm/str filter-id "-" index)

View file

@ -20,6 +20,8 @@
[app.main.ui.auth.recovery-request :refer [recovery-request-page recovery-sent-page]] [app.main.ui.auth.recovery-request :refer [recovery-request-page recovery-sent-page]]
[app.main.ui.auth.register :as register] [app.main.ui.auth.register :as register]
[app.main.ui.dashboard.sidebar :refer [sidebar]] [app.main.ui.dashboard.sidebar :refer [sidebar]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
[app.main.ui.ds.foundations.assets.raw-svg :refer [raw-svg*]]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.viewer.header :as viewer.header] [app.main.ui.viewer.header :as viewer.header]
[app.util.dom :as dom] [app.util.dom :as dom]
@ -43,9 +45,9 @@
[:button [:button
{:class (stl/css :exception-header) {:class (stl/css :exception-header)
:on-click on-nav-root} :on-click on-nav-root}
i/logo-icon [:> raw-svg* {:id "penpot-logo-icon" :class (stl/css :penpot-logo)}]
(when profile-id (when profile-id
(str "< " (tr "not-found.no-permission.go-dashboard")))] [:div {:class (stl/css :go-back-wrapper)} [:> icon* {:id "arrow" :class (stl/css :back-arrow)}] [:span (tr "not-found.no-permission.go-dashboard")]])]
[:div {:class (stl/css :deco-before)} i/logo-error-screen] [:div {:class (stl/css :deco-before)} i/logo-error-screen]
(when-not profile-id (when-not profile-id
[:button {:class (stl/css :login-header) [:button {:class (stl/css :login-header)

View file

@ -66,6 +66,7 @@
justify-content: flex-end; justify-content: flex-end;
height: 100%; height: 100%;
width: 25%; width: 25%;
padding-bottom: $s-28;
&:first-child { &:first-child {
text-align: right; text-align: right;
@ -82,12 +83,25 @@
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
}
svg { .penpot-logo {
fill: var(--color-foreground-primary); fill: var(--color-foreground-primary);
width: $s-48; width: $s-48;
height: auto; height: $s-48;
} }
.back-arrow {
transform: rotate(180deg);
}
.go-back-wrapper {
display: flex;
justify-content: center;
align-items: center;
gap: $s-8;
margin-left: $s-12;
font-size: $fs-14;
} }
.login-header { .login-header {

View file

@ -9,7 +9,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.config :as cf] [app.config :as cfg]
[app.main.data.events :as ev] [app.main.data.events :as ev]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.plugins :as dp] [app.main.data.plugins :as dp]
@ -169,7 +169,7 @@
[:> i18n/tr-html* [:> i18n/tr-html*
{:class (stl/css :discover) {:class (stl/css :discover)
:on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"})) :on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"}))
:content (tr "workspace.plugins.discover" cf/plugins-list-uri)}]) :content (tr "workspace.plugins.discover" cfg/plugins-list-uri)}])
[:hr] [:hr]
@ -178,7 +178,7 @@
[:div {:class (stl/css :plugins-empty-logo)} i/puzzle] [:div {:class (stl/css :plugins-empty-logo)} i/puzzle]
[:div {:class (stl/css :plugins-empty-text)} (tr "workspace.plugins.empty-plugins")] [:div {:class (stl/css :plugins-empty-text)} (tr "workspace.plugins.empty-plugins")]
[:a {:class (stl/css :plugins-link) [:a {:class (stl/css :plugins-link)
:href cf/plugins-list-uri :href cfg/plugins-list-uri
:target "_blank" :target "_blank"
:on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"}))} :on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"}))}
(tr "workspace.plugins.plugin-list-link") i/external-link]] (tr "workspace.plugins.plugin-list-link") i/external-link]]
@ -287,8 +287,9 @@
[:div {:class (stl/css :modal-content)} [:div {:class (stl/css :modal-content)}
[:& plugins-permission-list {:permissions permissions}] [:& plugins-permission-list {:permissions permissions}]
[:div {:class (stl/css :permissions-disclaimer)} (when-not (contains? cfg/plugins-whitelist host)
(tr "workspace.plugins.permissions.disclaimer")]] [:div {:class (stl/css :permissions-disclaimer)}
(tr "workspace.plugins.permissions.disclaimer")])]
[:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)} [:div {:class (stl/css :action-buttons)}

View file

@ -272,7 +272,7 @@ div.input-error {
@include bodySmallTypography; @include bodySmallTypography;
padding: $s-16; padding: $s-16;
background: var(--color-background-quaternary); background: var(--color-background-quaternary);
color: var(--color-foreground-quaternary); color: var(--color-foreground-primary);
border-radius: $br-4; border-radius: $br-4;
} }

View file

@ -138,6 +138,8 @@
first-selected-shape (first selected-shapes) first-selected-shape (first selected-shapes)
shape-parent-frame (cfh/get-frame objects (:frame-id first-selected-shape)) shape-parent-frame (cfh/get-frame objects (:frame-id first-selected-shape))
options-mode (mf/deref refs/options-mode-global)
on-change-tab on-change-tab
(fn [options-mode] (fn [options-mode]
(let [options-mode (keyword options-mode)] (let [options-mode (keyword options-mode)]
@ -187,6 +189,7 @@
[:> tab-switcher* {:tabs tabs [:> tab-switcher* {:tabs tabs
:default-selected "info" :default-selected "info"
:on-change-tab on-change-tab :on-change-tab on-change-tab
:selected (name options-mode)
:class (stl/css :options-tab-switcher)}]])) :class (stl/css :options-tab-switcher)}]]))
;; TODO: this need optimizations, selected-objects and ;; TODO: this need optimizations, selected-objects and

View file

@ -36,32 +36,37 @@
.constraints-bottom { .constraints-bottom {
@include flexCenter; @include flexCenter;
grid-area: top; grid-area: top;
.constraint-btn, }
.constraint-btn-special, .constraint-btn,
.constraint-btn-rotated { .constraint-btn-special,
@include buttonStyle; .constraint-btn-rotated {
@include flexCenter; @include buttonStyle;
width: 100%; @include flexCenter;
height: 100%; width: 100%;
.resalted-area { height: 100%;
width: $s-32; --resalted-area-background-color: var(--button-constraint-background-color-rest);
height: $s-3; --resalted-area-border-color: none;
border-radius: $br-8; &.active {
background-color: var(--button-constraint-background-color-rest); --resalted-area-border-color: var(--button-constraint-border-color-hover);
padding: 0; --resalted-area-background-color: var(--button-constraint-background-color-hover);
margin: 0; }
} &:hover,
&.active .resalted-area { &:focus-visible {
outline: $s-4 solid var(--button-constraint-border-color-hover); --resalted-area-border-color: var(--button-constraint-border-color-hover);
background-color: var(--button-constraint-background-color-hover); --resalted-area-background-color: var(--button-constraint-background-color-hover);
}
&:hover .resalted-area,
&:focus .resalted-area {
outline: $s-4 solid var(--button-constraint-border-color-hover);
background-color: var(--button-constraint-background-color-hover);
}
} }
} }
.resalted-area {
width: $s-32;
height: $s-3;
border-radius: $br-8;
background-color: var(--resalted-area-background-color);
outline: $s-4 solid var(--resalted-area-border-color);
padding: 0;
margin: 0;
}
.constraints-left { .constraints-left {
grid-area: left; grid-area: left;
.constraint-btn-rotated { .constraint-btn-rotated {
@ -73,6 +78,7 @@
} }
} }
} }
.constraints-center { .constraints-center {
grid-area: center; grid-area: center;
position: relative; position: relative;
@ -113,7 +119,7 @@
grid-area: bottom; grid-area: bottom;
} }
.contraints-selects { .constraints-selects {
@include flexColumn; @include flexColumn;
} }

View file

@ -677,7 +677,7 @@
[{:keys [type value]}] [{:keys [type value]}]
(case type (case type
:auto "auto" :auto "auto"
:percent (fmt/format-percent value) :percent (fmt/format-percent (/ value 100))
:flex (fmt/format-frs value) :flex (fmt/format-frs value)
:fixed (fmt/format-pixels value) :fixed (fmt/format-pixels value)
value)) value))

View file

@ -150,6 +150,7 @@
.grid-layout-menu { .grid-layout-menu {
@include flexColumn; @include flexColumn;
gap: $s-8; gap: $s-8;
overflow: hidden;
.row { .row {
@include flexRow; @include flexRow;

View file

@ -397,7 +397,7 @@
(->> @hover-ids (->> @hover-ids
(filter #(cfh/frame-shape? (get base-objects %))) (filter #(cfh/frame-shape? (get base-objects %)))
(remove selected) (remove selected)
(first)) (last))
outlined-frame (get objects outlined-frame-id)] outlined-frame (get objects outlined-frame-id)]
[:* [:*
[:& outline/shape-outlines [:& outline/shape-outlines

View file

@ -7,6 +7,9 @@ export DEVENV_PNAME="penpotdev";
export CURRENT_USER_ID=$(id -u); export CURRENT_USER_ID=$(id -u);
export CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD); export CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD);
# Set default java options
export JAVA_OPTS=${JAVA_OPTS:-"-Xmx1000m -Xms50m"};
set -e set -e
function print-current-version { function print-current-version {
@ -95,10 +98,12 @@ function run-devenv-shell {
if [[ ! $(docker ps -f "name=penpot-devenv-main" -q) ]]; then if [[ ! $(docker ps -f "name=penpot-devenv-main" -q) ]]; then
start-devenv start-devenv
fi fi
docker exec -ti penpot-devenv-main sudo -EH -u penpot bash docker exec -ti \
-e JAVA_OPTS="$JAVA_OPTS" \
-e EXTERNAL_UID=$CURRENT_USER_ID \
penpot-devenv-main sudo -EH -u penpot bash;
} }
function build { function build {
echo ">> build start: $1" echo ">> build start: $1"
local version=$(print-current-version); local version=$(print-current-version);
@ -111,6 +116,7 @@ function build {
-e EXTERNAL_UID=$CURRENT_USER_ID \ -e EXTERNAL_UID=$CURRENT_USER_ID \
-e BUILD_STORYBOOK=$BUILD_STORYBOOK \ -e BUILD_STORYBOOK=$BUILD_STORYBOOK \
-e SHADOWCLJS_EXTRA_PARAMS=$SHADOWCLJS_EXTRA_PARAMS \ -e SHADOWCLJS_EXTRA_PARAMS=$SHADOWCLJS_EXTRA_PARAMS \
-e JAVA_OPTS="$JAVA_OPTS" \
-w /home/penpot/penpot/$1 \ -w /home/penpot/penpot/$1 \
$DEVENV_IMGNAME:latest sudo -EH -u penpot ./scripts/build $version $DEVENV_IMGNAME:latest sudo -EH -u penpot ./scripts/build $version