diff --git a/patches/0003-sparkles-Add-option-to-download-user-uploaded-custom.patch b/patches/0003-sparkles-Add-option-to-download-user-uploaded-custom.patch deleted file mode 100644 index 86c5f6fa3d3..00000000000 --- a/patches/0003-sparkles-Add-option-to-download-user-uploaded-custom.patch +++ /dev/null @@ -1,225 +0,0 @@ -From 41015b5700af932e68f9cc5fa4b5444ba7fe2ed1 Mon Sep 17 00:00:00 2001 -From: Dalai Felinto -Date: Tue, 10 Feb 2026 23:31:32 +0100 -Subject: [PATCH 3/4] sparkles: Add option to download user uploaded custom - fonts - -cherry-pick from: c55c23c6d ---- - backend/src/app/rpc/commands/fonts.clj | 96 ++++++++++++++++++- - frontend/src/app/main/ui/dashboard/fonts.cljs | 38 +++++++- - frontend/translations/en.po | 3 + - 3 files changed, 134 insertions(+), 3 deletions(-) - -diff --git a/backend/src/app/rpc/commands/fonts.clj b/backend/src/app/rpc/commands/fonts.clj -index 03c66a968..f646342cc 100644 ---- a/backend/src/app/rpc/commands/fonts.clj -+++ b/backend/src/app/rpc/commands/fonts.clj -@@ -9,6 +9,7 @@ - [app.binfile.common :as bfc] - [app.common.data.macros :as dm] - [app.common.exceptions :as ex] -+ [app.common.media :as cmedia] - [app.common.schema :as sm] - [app.common.time :as ct] - [app.common.uuid :as uuid] -@@ -31,10 +32,13 @@ - [app.util.services :as sv] - [datoteka.io :as io]) - (:import -+ java.io.ByteArrayOutputStream - java.io.InputStream - java.io.OutputStream - java.io.SequenceInputStream -- java.util.Collections)) -+ java.util.Collections -+ java.util.zip.ZipEntry -+ java.util.zip.ZipOutputStream)) - - (set! *warn-on-reflection* true) - -@@ -296,3 +300,93 @@ - (rph/with-meta (rph/wrap) - {::audit/props {:font-family (:font-family variant) - :font-id (:font-id variant)}}))) -+ -+;; --- DOWNLOAD FONT -+ -+(def ^:private schema:download-font -+ [:map {:title "download-font"} -+ [:id ::sm/uuid]]) -+ -+(sv/defmethod ::download-font -+ {::doc/added "1.18" -+ ::sm/params schema:download-font} -+ [{:keys [::sto/storage ::db/pool] :as cfg} {:keys [::rpc/profile-id id]}] -+ (dm/with-open [conn (db/open pool)] -+ (let [variant (db/get conn :team-font-variant -+ {:id id -+ :deleted-at nil})] -+ (when-not variant -+ (ex/raise :type :not-found -+ :code :object-not-found)) -+ -+ (teams/check-read-permissions! conn profile-id (:team-id variant)) -+ -+ ;; Try to get the best available font format (prefer TTF for broader compatibility). -+ (let [file-id (or (:ttf-file-id variant) -+ (:otf-file-id variant) -+ (:woff2-file-id variant) -+ (:woff1-file-id variant))] -+ (when-not file-id -+ (ex/raise :type :not-found -+ :code :font-file-not-found)) -+ -+ (let [font-obj (sto/get-object storage file-id) -+ font-bytes (sto/get-object-bytes storage font-obj)] -+ (when-not font-obj -+ (ex/raise :type :not-found -+ :code :font-file-not-found)) -+ -+ ;; Return base64-encoded string and mime-type for transit serialization. -+ (let [data (.encodeToString (java.util.Base64/getEncoder) font-bytes) -+ mtype (or (:content-type font-obj) (-> font-obj meta :content-type) "application/octet-stream")] -+ {:data data :mtype mtype})))))) -+ -+(def ^:private schema:download-font-family -+ [:map {:title "download-font-family"} -+ [:font-id ::sm/uuid]]) -+ -+(sv/defmethod ::download-font-family -+ {::doc/added "1.18" -+ ::sm/params schema:download-font-family} -+ [{:keys [::sto/storage ::db/pool] :as cfg} {:keys [::rpc/profile-id font-id]}] -+ (dm/with-open [conn (db/open pool)] -+ (let [variants (db/query conn :team-font-variant -+ {:font-id font-id -+ :deleted-at nil})] -+ (when-not (seq variants) -+ (ex/raise :type :not-found -+ :code :object-not-found)) -+ -+ (teams/check-read-permissions! conn profile-id (:team-id (first variants))) -+ -+ (let [entries -+ (->> variants -+ (map (fn [v] -+ (let [file-id (or (:ttf-file-id v) -+ (:otf-file-id v) -+ (:woff2-file-id v) -+ (:woff1-file-id v))] -+ (when-not file-id -+ (ex/raise :type :not-found :code :font-file-not-found)) -+ -+ (let [sobj (sto/get-object storage file-id) -+ bytes (sto/get-object-bytes storage sobj) -+ mtype (or (:content-type sobj) (-> sobj meta :content-type) "application/octet-stream") -+ ext (cmedia/mtype->extension mtype) -+ name (str (:font-family v) "-" (:font-weight v) -+ (when-not (= "normal" (:font-style v)) (str "-" (:font-style v))) -+ (or ext ""))] -+ {:name name :bytes bytes})))))] -+ -+ ;; Build zip in memory. -+ (let [baos (ByteArrayOutputStream.) -+ zos (ZipOutputStream. baos)] -+ (doseq [{:keys [name bytes]} entries] -+ (let [entry (ZipEntry. name)] -+ (.putNextEntry zos entry) -+ (.write zos ^bytes bytes) -+ (.closeEntry zos))) -+ (.close zos) -+ (let [zip-bytes (.toByteArray baos) -+ data (.encodeToString (java.util.Base64/getEncoder) zip-bytes)] -+ {:data data :mtype "application/zip"})))))) -\ No newline at end of file -diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs -index f84d69489..26794f8c2 100644 ---- a/frontend/src/app/main/ui/dashboard/fonts.cljs -+++ b/frontend/src/app/main/ui/dashboard/fonts.cljs -@@ -24,6 +24,8 @@ - [app.util.dom :as dom] - [app.util.i18n :as i18n :refer [tr]] - [app.util.keyboard :as kbd] -+ [app.util.timers :as tm] -+ [app.util.webapi :as wapi] - [beicon.v2.core :as rx] - [cuerdas.core :as str] - [okulary.core :as l] -@@ -259,11 +261,14 @@ - (mf/defc installed-font-context-menu - {::mf/props :obj - ::mf/private true} -- [{:keys [is-open on-close on-edit on-delete]}] -- (let [options (mf/with-memo [on-edit on-delete] -+ [{:keys [is-open on-close on-edit on-download on-delete]}] -+ (let [options (mf/with-memo [on-edit on-download on-delete] - [{:name (tr "labels.edit") - :id "font-edit" - :handler on-edit} -+ {:name (tr "labels.download-simple") -+ :id "font-download" -+ :handler on-download} - {:name (tr "labels.delete") - :id "font-delete" - :handler on-delete}])] -@@ -345,6 +350,34 @@ - (st/emit! (df/delete-font font-id)))}] - (st/emit! (modal/show options))))) - -+ on-download -+ (mf/use-fn -+ (mf/deps variants) -+ (fn [_event] -+ (let [variant (first variants) -+ variant-id (:id variant) -+ multiple? (> (count variants) 1) -+ cmd (if multiple? :download-font-family :download-font) -+ params (if multiple? {:font-id font-id} {:id variant-id})] -+ (->> (rp/cmd! cmd params) -+ (rx/subs! (fn [font-data] -+ ;; font-data is base64-encoded or a map {:data :mtype} -+ (let [b64 (if (string? font-data) font-data (:data font-data)) -+ default-mtype "application/octet-stream" -+ mtype (if (string? font-data) default-mtype (or (:mtype font-data) default-mtype)) -+ binary-str (js/atob b64) -+ bytes (js/Uint8Array. -+ (for [i (range (.-length binary-str))] -+ (.charCodeAt binary-str i))) -+ blob (wapi/create-blob bytes mtype) -+ uri (wapi/create-uri blob) -+ name (:font-family font)] -+ (dom/trigger-download-uri name mtype uri) -+ (tm/schedule-on-idle #(wapi/revoke-uri uri)))) -+ (fn [error] -+ (js/console.error "error downloading font" error) -+ (st/emit! (ntf/error (tr "errors.download-font"))))))))) -+ - on-delete-variant - (mf/use-fn - (fn [event] -@@ -407,6 +440,7 @@ - {:on-close on-menu-close - :is-open menu-open? - :on-delete on-delete-font -+ :on-download on-download - :on-edit on-edit}]]))])) - - (mf/defc installed-fonts* -diff --git a/frontend/translations/en.po b/frontend/translations/en.po -index ccbe93d5d..97a62128c 100644 ---- a/frontend/translations/en.po -+++ b/frontend/translations/en.po -@@ -2373,6 +2373,9 @@ msgid "labels.download" - msgstr "Download %s" - - #: src/app/main/ui/dashboard/file_menu.cljs:30, src/app/main/ui/dashboard/files.cljs:80, src/app/main/ui/dashboard/files.cljs:179, src/app/main/ui/dashboard/projects.cljs:229, src/app/main/ui/dashboard/projects.cljs:233, src/app/main/ui/dashboard/sidebar.cljs:820 -+msgid "labels.download-simple" -+msgstr "Download" -+ - msgid "labels.drafts" - msgstr "Drafts" - --- -2.53.0 -