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

This commit is contained in:
Alejandro Alonso 2026-09-03 12:24:44 +02:00
commit 37f1d3f0fd
8 changed files with 52 additions and 23 deletions

View File

@ -241,6 +241,18 @@
(some-> (db/get cfg :file-data {:file-id file-id :id fragment-id :type "fragment"}) (some-> (db/get cfg :file-data {:file-id file-id :id fragment-id :type "fragment"})
(update :data blob/decode))) (update :data blob/decode)))
(defn- check-fragment-scope!
"Checks that the fragment is reachable from the pages authorized by
the share-link. Raises a :not-found exception if the fragment is not reachable."
[cfg file-id fragment-id pages]
(let [fdata (-> (bfc/get-file cfg file-id :read-only? true)
(get :data)
(update :pages-index select-keys pages))]
(when-not (contains? (feat.fdata/get-used-pointer-ids fdata) fragment-id)
(ex/raise :type :not-found
:code :object-not-found
:hint "object not found"))))
(sv/defmethod ::get-file-fragment (sv/defmethod ::get-file-fragment
"Retrieve a file fragment by its ID. Only authenticated users." "Retrieve a file fragment by its ID. Only authenticated users."
{::doc/added "1.17" {::doc/added "1.17"
@ -250,11 +262,9 @@
[cfg {:keys [::rpc/profile-id file-id fragment-id share-id]}] [cfg {:keys [::rpc/profile-id file-id fragment-id share-id]}]
(db/run! cfg (fn [cfg] (db/run! cfg (fn [cfg]
(let [perms (perms/get-file-read-permissions cfg profile-id file-id share-id)] (let [perms (perms/get-file-read-permissions cfg profile-id file-id share-id)]
(when (= :share-link (:type perms))
(ex/raise :type :not-found
:code :object-not-found
:hint "object not found"))
(check-read-permissions! perms) (check-read-permissions! perms)
(when (= :share-link (:type perms))
(check-fragment-scope! cfg file-id fragment-id (:pages perms)))
(-> (get-file-fragment cfg file-id fragment-id) (-> (get-file-fragment cfg file-id fragment-id)
(rph/with-http-cache long-cache-duration)))))) (rph/with-http-cache long-cache-duration))))))

View File

@ -326,11 +326,12 @@
(filter #(= page-id (:page-id %))) (filter #(= page-id (:page-id %)))
(d/index-by :id) (d/index-by :id)
(assoc state :comment-threads))) (assoc state :comment-threads)))
(on-error [{:keys [type] :as err}] (on-error [cause]
(if (or (= :authentication type) (let [{:keys [type]} (ex-data cause)]
(= :not-found type)) (if (or (= :authentication type)
(rx/empty) (= :not-found type))
(rx/throw err)))] (rx/empty)
(rx/throw cause))))]
(ptk/reify ::fetch-comment-threads (ptk/reify ::fetch-comment-threads
ptk/WatchEvent ptk/WatchEvent

View File

@ -114,6 +114,7 @@
(str "<ul>" items "</ul>"))] (str "<ul>" items "</ul>"))]
(st/emit! (ntf/show {:content (tr "errors.weak-password") (st/emit! (ntf/show {:content (tr "errors.weak-password")
:detail detail :detail detail
:is-html true
:type :toast :type :toast
:level :error}))) :level :error})))

View File

@ -120,7 +120,7 @@
[:div [:div
(tr "nitrate.code-activation.footer-after") " " (tr "nitrate.code-activation.footer-after") " "
[:a {:class (stl/css :link) [:a {:class (stl/css :link)
:href "mailto:sales@nitrate.com"} :href "mailto:sales@penpot.app"}
"sales@nitrate.com"] "sales@penpot.app"]
" " " "
(tr "nitrate.code-activation.footer-before")]]]]])) (tr "nitrate.code-activation.footer-before")]]]]]))

View File

@ -118,8 +118,8 @@
(tr "nitrate.form.contact-upgrade") (tr "nitrate.form.contact-upgrade")
(tr "nitrate.form.contact-trial"))] (tr "nitrate.form.contact-trial"))]
[:p {:class (stl/css :modal-text-large)} [:p {:class (stl/css :modal-text-large)}
[:a {:class (stl/css :link) :href "mailto:sales@penpot.app"} [:a {:class (stl/css :link) :href "mailto:sales@penpot.net"}
"sales@penpot.app"]] "sales@penpot.net"]]
[:div {:class (stl/css :activation-code)} [:div {:class (stl/css :activation-code)}
[:p {:class (stl/css :modal-text-large)} [:p {:class (stl/css :modal-text-large)}
[:a {:class (stl/css :link) [:a {:class (stl/css :link)

View File

@ -745,7 +745,6 @@
:cta-link (if (and (contains? cf/flags :admin-console) nitrate?) #(open-contact-sales-modal subscription-type "Unlimited") #(open-subscription-modal "unlimited" subscription)) :cta-link (if (and (contains? cf/flags :admin-console) nitrate?) #(open-contact-sales-modal subscription-type "Unlimited") #(open-subscription-modal "unlimited" subscription))
:cta-text-with-icon (tr "subscription.settings.more-information") :cta-text-with-icon (tr "subscription.settings.more-information")
:cta-link-with-icon go-to-pricing-page :cta-link-with-icon go-to-pricing-page
:recommended (= subscription-type "professional")
:show-button-cta (= subscription-type "professional") :show-button-cta (= subscription-type "professional")
:current-plan false}]) :current-plan false}])
@ -783,6 +782,7 @@
:cta-text-with-icon (tr "subscription.settings.more-information") :cta-text-with-icon (tr "subscription.settings.more-information")
:cta-link-with-icon go-to-pricing-page :cta-link-with-icon go-to-pricing-page
:code-action :activate :code-action :activate
:recommended (= subscription-type "professional")
:show-button-cta (not nitrate-license) :show-button-cta (not nitrate-license)
:current-plan false :current-plan false
:inline-error nitrate-start-error-message}])]]])) :inline-error nitrate-start-error-message}])]]]))
@ -848,8 +848,8 @@
[:div {:class (stl/css :modal-text)} [:div {:class (stl/css :modal-text)}
(tr "nitrate.form.enterprise-intro" ".") " " (if nitrate-license (tr "nitrate.form.contact-us-upgrade") (tr "nitrate.form.contact-us-free-trial"))] (tr "nitrate.form.enterprise-intro" ".") " " (if nitrate-license (tr "nitrate.form.contact-us-upgrade") (tr "nitrate.form.contact-us-free-trial"))]
[:div {:class (stl/css :modal-text)} [:div {:class (stl/css :modal-text)}
[:a {:class (stl/css :cta-button) :href "mailto:sales@penpot.app"} [:a {:class (stl/css :cta-button) :href "mailto:sales@penpot.net"}
"sales@penpot.app"]]])]])) "sales@penpot.net"]]])]]))
(mf/defc nitrate-contact-sales-dialog (mf/defc nitrate-contact-sales-dialog
{::mf/register modal/components {::mf/register modal/components
@ -898,7 +898,7 @@
:on-click handle-close-dialog} (tr "ds.confirm-cancel")] :on-click handle-close-dialog} (tr "ds.confirm-cancel")]
[:> button* {:variant "primary" [:> button* {:variant "primary"
:type "button" :type "button"
:on-click #(dom/open-new-window (dm/str "mailto:sales@penpot.app?subject=Switch%20to%20the%20" subscription-type "%20plan"))} (tr "nitrate.contact-sales.button")]]])]]])) :on-click #(dom/open-new-window (dm/str "mailto:sales@penpot.net?subject=Switch%20to%20the%20" subscription-type "%20plan"))} (tr "nitrate.contact-sales.button")]]])]]]))
(mf/defc nitrate-cancel-contact-sales-dialog (mf/defc nitrate-cancel-contact-sales-dialog
{::mf/register modal/components {::mf/register modal/components

View File

@ -164,11 +164,13 @@
(defn- sample-container-style (defn- sample-container-style
"Inline style that applies the typography font to the (clipped, fixed-height) "Inline style that applies the typography font to the (clipped, fixed-height)
sample container." sample container. Must be a real JS object (`#js`), not a ClojureScript map:
the `:style` value here is a runtime expression, not a literal recognized by
the hiccup macro, so it reaches React unconverted."
[typography] [typography]
{:font-family (:font-family typography) #js {:fontFamily (:font-family typography)
:font-weight (:font-weight typography) :fontWeight (:font-weight typography)
:font-style (:font-style typography)}) :fontStyle (:font-style typography)})
(defn- sample-text-style (defn- sample-text-style
"Inline style that optically centers the sample glyphs. Must be applied to "Inline style that optically centers the sample glyphs. Must be applied to
@ -177,7 +179,7 @@
would shift the whole box relative to the row instead of the glyphs inside it." would shift the whole box relative to the row instead of the glyphs inside it."
[em] [em]
(when-not (zero? em) (when-not (zero? em)
{:transform (dm/str "translateY(" em "em)")})) #js {:transform (dm/str "translateY(" em "em)")}))
;; --- FONT SELECTOR -------------------------------------------------------- ;; --- FONT SELECTOR --------------------------------------------------------
@ -219,6 +221,7 @@
:role "img" :role "img"
:aria-label (:name font)} :aria-label (:name font)}
[:use {:href (dm/str "#" fonts/preview-sprite-prefix font-id)}]] [:use {:href (dm/str "#" fonts/preview-sprite-prefix font-id)}]]
<<<<<<< HEAD
[:span {:class (stl/css :font-item-label) [:span {:class (stl/css :font-item-label)
:style (cond-> {} :style (cond-> {}
loaded? loaded?
@ -226,6 +229,20 @@
(not (zero? label-offset)) (not (zero? label-offset))
(assoc :transform (dm/str "translateY(" label-offset "em)")))} (assoc :transform (dm/str "translateY(" label-offset "em)")))}
(:name font)]))) (:name font)])))
=======
;; The vertical correction goes on an INNER span, not on `.font-item-label`
;; itself: that class carries its own `overflow: hidden` (from the
;; text-ellipsis mixin, needed to truncate long font names), and a
;; transform applied to a self-clipping element moves its clip region
;; along with it — a no-op. The inner span has no overflow of its own, so
;; the shift actually moves the ink within the outer's fixed clip area.
[:span {:class (stl/css :font-item-label)}
[:span {:style #js {:fontFamily (when loaded?
(dm/str "\"" (:family font) "\", sans-serif"))
:transform (when-not (zero? label-offset)
(dm/str "translateY(" label-offset "em)"))}}
(:name font)]])))
>>>>>>> origin/staging
(mf/defc font-item* (mf/defc font-item*
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}

View File

@ -101,7 +101,7 @@ $font-preview-box-height: 28px;
box-sizing: border-box; box-sizing: border-box;
background-color: var(--font-name-wrapper-background-color); background-color: var(--font-name-wrapper-background-color);
margin-block-end: var(--sp-s); margin-block-end: var(--sp-s);
padding: var(--sp-s) 0 var(--sp-s) var(--sp-m); padding-inline-start: var(--sp-m);
&:focus-within { &:focus-within {
--font-name-wrapper-border-color: var(--color-accent-primary); --font-name-wrapper-border-color: var(--color-accent-primary);