diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 366ba96499..9b518ca9d6 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -241,6 +241,18 @@ (some-> (db/get cfg :file-data {:file-id file-id :id fragment-id :type "fragment"}) (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 "Retrieve a file fragment by its ID. Only authenticated users." {::doc/added "1.17" @@ -250,11 +262,9 @@ [cfg {:keys [::rpc/profile-id file-id fragment-id share-id]}] (db/run! cfg (fn [cfg] (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) + (when (= :share-link (:type perms)) + (check-fragment-scope! cfg file-id fragment-id (:pages perms))) (-> (get-file-fragment cfg file-id fragment-id) (rph/with-http-cache long-cache-duration)))))) diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index 5b92a20316..4ad40beade 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -326,11 +326,12 @@ (filter #(= page-id (:page-id %))) (d/index-by :id) (assoc state :comment-threads))) - (on-error [{:keys [type] :as err}] - (if (or (= :authentication type) - (= :not-found type)) - (rx/empty) - (rx/throw err)))] + (on-error [cause] + (let [{:keys [type]} (ex-data cause)] + (if (or (= :authentication type) + (= :not-found type)) + (rx/empty) + (rx/throw cause))))] (ptk/reify ::fetch-comment-threads ptk/WatchEvent diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index 68a2ac22b1..e6cd8197f5 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -114,6 +114,7 @@ (str ""))] (st/emit! (ntf/show {:content (tr "errors.weak-password") :detail detail + :is-html true :type :toast :level :error}))) diff --git a/frontend/src/app/main/ui/nitrate/nitrate_code_activation_modal.cljs b/frontend/src/app/main/ui/nitrate/nitrate_code_activation_modal.cljs index 1ede96a4d6..5d8f51a51f 100644 --- a/frontend/src/app/main/ui/nitrate/nitrate_code_activation_modal.cljs +++ b/frontend/src/app/main/ui/nitrate/nitrate_code_activation_modal.cljs @@ -120,7 +120,7 @@ [:div (tr "nitrate.code-activation.footer-after") " " [:a {:class (stl/css :link) - :href "mailto:sales@nitrate.com"} - "sales@nitrate.com"] + :href "mailto:sales@penpot.app"} + "sales@penpot.app"] " " (tr "nitrate.code-activation.footer-before")]]]]])) diff --git a/frontend/src/app/main/ui/nitrate/nitrate_form.cljs b/frontend/src/app/main/ui/nitrate/nitrate_form.cljs index 93e3a61eda..489ba391b9 100644 --- a/frontend/src/app/main/ui/nitrate/nitrate_form.cljs +++ b/frontend/src/app/main/ui/nitrate/nitrate_form.cljs @@ -118,8 +118,8 @@ (tr "nitrate.form.contact-upgrade") (tr "nitrate.form.contact-trial"))] [:p {:class (stl/css :modal-text-large)} - [:a {:class (stl/css :link) :href "mailto:sales@penpot.app"} - "sales@penpot.app"]] + [:a {:class (stl/css :link) :href "mailto:sales@penpot.net"} + "sales@penpot.net"]] [:div {:class (stl/css :activation-code)} [:p {:class (stl/css :modal-text-large)} [:a {:class (stl/css :link) diff --git a/frontend/src/app/main/ui/settings/subscription.cljs b/frontend/src/app/main/ui/settings/subscription.cljs index a8a7f3fed9..ff38ffb1c6 100644 --- a/frontend/src/app/main/ui/settings/subscription.cljs +++ b/frontend/src/app/main/ui/settings/subscription.cljs @@ -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-text-with-icon (tr "subscription.settings.more-information") :cta-link-with-icon go-to-pricing-page - :recommended (= subscription-type "professional") :show-button-cta (= subscription-type "professional") :current-plan false}]) @@ -783,6 +782,7 @@ :cta-text-with-icon (tr "subscription.settings.more-information") :cta-link-with-icon go-to-pricing-page :code-action :activate + :recommended (= subscription-type "professional") :show-button-cta (not nitrate-license) :current-plan false :inline-error nitrate-start-error-message}])]]])) @@ -848,8 +848,8 @@ [: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"))] [:div {:class (stl/css :modal-text)} - [:a {:class (stl/css :cta-button) :href "mailto:sales@penpot.app"} - "sales@penpot.app"]]])]])) + [:a {:class (stl/css :cta-button) :href "mailto:sales@penpot.net"} + "sales@penpot.net"]]])]])) (mf/defc nitrate-contact-sales-dialog {::mf/register modal/components @@ -898,7 +898,7 @@ :on-click handle-close-dialog} (tr "ds.confirm-cancel")] [:> button* {:variant "primary" :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/register modal/components 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 b73d9dab19..8a8e41354c 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 @@ -164,11 +164,13 @@ (defn- sample-container-style "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] - {:font-family (:font-family typography) - :font-weight (:font-weight typography) - :font-style (:font-style typography)}) + #js {:fontFamily (:font-family typography) + :fontWeight (:font-weight typography) + :fontStyle (:font-style typography)}) (defn- sample-text-style "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." [em] (when-not (zero? em) - {:transform (dm/str "translateY(" em "em)")})) + #js {:transform (dm/str "translateY(" em "em)")})) ;; --- FONT SELECTOR -------------------------------------------------------- @@ -219,6 +221,7 @@ :role "img" :aria-label (:name font)} [:use {:href (dm/str "#" fonts/preview-sprite-prefix font-id)}]] +<<<<<<< HEAD [:span {:class (stl/css :font-item-label) :style (cond-> {} loaded? @@ -226,6 +229,20 @@ (not (zero? label-offset)) (assoc :transform (dm/str "translateY(" label-offset "em)")))} (: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/wrap [mf/memo]} 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 a8ad4b21ef..bbfa19734e 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 @@ -101,7 +101,7 @@ $font-preview-box-height: 28px; box-sizing: border-box; background-color: var(--font-name-wrapper-background-color); 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 { --font-name-wrapper-border-color: var(--color-accent-primary);