From 547750e8bfe409281c3a52ac56d353387c44c778 Mon Sep 17 00:00:00 2001 From: Statxc Date: Thu, 30 Apr 2026 15:29:04 +0200 Subject: [PATCH] :bug: Preserve OpenType variant name for custom fonts (#9193) --- CHANGES.md | 1 + backend/src/app/migrations.clj | 5 ++- ...148-add-variant-name-team-font-variant.sql | 2 ++ backend/src/app/rpc/commands/fonts.clj | 4 ++- common/src/app/common/media.cljc | 12 +++++++ common/test/common_tests/media_test.cljc | 35 +++++++++++++++++++ frontend/src/app/main/data/fonts.cljs | 7 ++-- frontend/src/app/main/ui/dashboard/fonts.cljs | 7 ++-- 8 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 backend/src/app/migrations/sql/0148-add-variant-name-team-font-variant.sql diff --git a/CHANGES.md b/CHANGES.md index d7c499c5f4..a6f7459acf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -71,6 +71,7 @@ - Remove `corepack` from the MCP local launcher so it runs on Node.js 25+, where corepack is no longer bundled [Github #8877](https://github.com/penpot/penpot/issues/8877) - Fix Copy as SVG: emit a single valid SVG document when multiple shapes are selected, and publish `image/svg+xml` to the clipboard so the paste target works in Inkscape and other SVG-native tools [Github #838](https://github.com/penpot/penpot/issues/838) - Reset profile submenu state when the account menu closes (by @eureka0928) [Github #8947](https://github.com/penpot/penpot/issues/8947) +- Preserve OpenType variant name table for custom fonts in the dashboard [Github #8924](https://github.com/penpot/penpot/issues/8924) - Add export panel to inspect styles tab [Taiga #13582](https://tree.taiga.io/project/penpot/issue/13582) - Fix styles between grid layout inputs [Taiga #13526](https://tree.taiga.io/project/penpot/issue/13526) - Fix id prop on switch component [Taiga #13534](https://tree.taiga.io/project/penpot/issue/13534) diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj index 7554618cdd..a188c3c1f0 100644 --- a/backend/src/app/migrations.clj +++ b/backend/src/app/migrations.clj @@ -475,7 +475,10 @@ :fn (mg/resource "app/migrations/sql/0147-mod-team-invitation-table.sql")} {:name "0147-add-upload-session-table" - :fn (mg/resource "app/migrations/sql/0147-add-upload-session-table.sql")}]) + :fn (mg/resource "app/migrations/sql/0147-add-upload-session-table.sql")} + + {:name "0148-add-variant-name-team-font-variant" + :fn (mg/resource "app/migrations/sql/0148-add-variant-name-team-font-variant.sql")}]) (defn apply-migrations! [pool name migrations] diff --git a/backend/src/app/migrations/sql/0148-add-variant-name-team-font-variant.sql b/backend/src/app/migrations/sql/0148-add-variant-name-team-font-variant.sql new file mode 100644 index 0000000000..d90fb83538 --- /dev/null +++ b/backend/src/app/migrations/sql/0148-add-variant-name-team-font-variant.sql @@ -0,0 +1,2 @@ +ALTER TABLE team_font_variant + ADD COLUMN variant_name text NULL; diff --git a/backend/src/app/rpc/commands/fonts.clj b/backend/src/app/rpc/commands/fonts.clj index b47c6c2e38..e8c759fed7 100644 --- a/backend/src/app/rpc/commands/fonts.clj +++ b/backend/src/app/rpc/commands/fonts.clj @@ -98,7 +98,8 @@ [:font-id ::sm/uuid] [:font-family ::sm/text] [:font-weight [::sm/one-of {:format "number"} valid-weight]] - [:font-style [::sm/one-of {:format "string"} valid-style]]]) + [:font-style [::sm/one-of {:format "string"} valid-style]] + [:variant-name {:optional true} [:maybe ::sm/text]]]) ;; FIXME: IMPORTANT: refactor this, we should not hold a whole db ;; connection around the font creation @@ -184,6 +185,7 @@ :font-family (:font-family params) :font-weight (:font-weight params) :font-style (:font-style params) + :variant-name (:variant-name params) :woff1-file-id (:id woff1) :woff2-file-id (:id woff2) :otf-file-id (:id otf) diff --git a/common/src/app/common/media.cljc b/common/src/app/common/media.cljc index fc349765a2..87d7b2f401 100644 --- a/common/src/app/common/media.cljc +++ b/common/src/app/common/media.cljc @@ -114,3 +114,15 @@ 800 "Extra Bold" 900 "Black" 950 "Extra Black")) + +(defn font-display-variant + [variant-name weight style] + (cond + (and (string? variant-name) (not (str/blank? variant-name))) + (str/trim variant-name) + + :else + (let [base (font-weight->name weight) + italic? (= "italic" style)] + (cond-> base + italic? (str " Italic"))))) diff --git a/common/test/common_tests/media_test.cljc b/common/test/common_tests/media_test.cljc index b6c18aab2d..a41d2466fa 100644 --- a/common/test/common_tests/media_test.cljc +++ b/common/test/common_tests/media_test.cljc @@ -57,3 +57,38 @@ (t/testing "leaves filename intact when it has no extension" (t/is (= (media/strip-image-extension "README") "README")))) + +(t/deftest test-font-display-variant + (t/testing "preserves the foundry-supplied variant string verbatim" + (t/is (= "Thin" (media/font-display-variant "Thin" 100 "normal"))) + (t/is (= "SemiBold" (media/font-display-variant "SemiBold" 600 "normal"))) + (t/is (= "Medium Oblique" (media/font-display-variant "Medium Oblique" 500 "italic"))) + (t/is (= "Ultra" (media/font-display-variant "Ultra" 900 "normal")))) + + (t/testing "trims surrounding whitespace from upstream variant strings" + (t/is (= "Bold" (media/font-display-variant " Bold " 700 "normal")))) + + (t/testing "ignores blank or nil variant strings" + (t/is (= "Hairline" (media/font-display-variant nil 100 "normal"))) + (t/is (= "Regular" (media/font-display-variant "" 400 "normal"))) + (t/is (= "Bold" (media/font-display-variant " " 700 "normal"))) + (t/is (= "Bold Italic" (media/font-display-variant nil 700 "italic")))) + + (t/testing "fallback covers every supported numeric weight" + (t/is (= "Hairline" (media/font-display-variant nil 100 "normal"))) + (t/is (= "Extra Light" (media/font-display-variant nil 200 "normal"))) + (t/is (= "Light" (media/font-display-variant nil 300 "normal"))) + (t/is (= "Regular" (media/font-display-variant nil 400 "normal"))) + (t/is (= "Medium" (media/font-display-variant nil 500 "normal"))) + (t/is (= "Semi Bold" (media/font-display-variant nil 600 "normal"))) + (t/is (= "Bold" (media/font-display-variant nil 700 "normal"))) + (t/is (= "Extra Bold" (media/font-display-variant nil 800 "normal"))) + (t/is (= "Black" (media/font-display-variant nil 900 "normal"))) + (t/is (= "Extra Black" (media/font-display-variant nil 950 "normal")))) + + (t/testing "italic suffix only applied via the fallback path" + (t/is (= "Italic" (media/font-display-variant "Italic" 400 "italic"))) + (t/is (= "Regular Italic" (media/font-display-variant nil 400 "italic")))) + + (t/testing "stored variant survives even when its derived weight disagrees" + (t/is (= "Ultra" (media/font-display-variant "Ultra" 400 "normal"))))) diff --git a/frontend/src/app/main/data/fonts.cljs b/frontend/src/app/main/data/fonts.cljs index d72cde8436..9a49711e85 100644 --- a/frontend/src/app/main/data/fonts.cljs +++ b/frontend/src/app/main/data/fonts.cljs @@ -60,9 +60,9 @@ (prepare-font-variant [item] {:id (str (:font-style item) "-" (:font-weight item)) - :name (str (cm/font-weight->name (:font-weight item)) - (when (not= "normal" (:font-style item)) - (str " " (str/capital (:font-style item))))) + :name (cm/font-display-variant (:variant-name item) + (:font-weight item) + (:font-style item)) :style (:font-style item) :weight (str (:font-weight item)) ::fonts/woff1-file-id (:woff1-file-id item) @@ -140,6 +140,7 @@ :font-family (or family "") :font-weight (cm/parse-font-weight variant) :font-style (cm/parse-font-style variant) + :variant-name variant :height-warning? height-warning?}) ;; Font could not be parsed (woff2), extract metadata from filename (let [base-name (str/replace name #"\.[^.]+$" "") diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs index 72c57856b9..eaefe3925f 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -65,10 +65,9 @@ (mf/defc font-variant-display-name* {::mf/private true} [{:keys [variant]}] - [:* - [:span (cm/font-weight->name (:font-weight variant))] - (when (not= "normal" (:font-style variant)) - [:span " " (str/capital (:font-style variant))])]) + [:span (cm/font-display-variant (:variant-name variant) + (:font-weight variant) + (:font-style variant))]) (mf/defc uploaded-fonts* {::mf/private true}