mirror of
https://github.com/penpot/penpot.git
synced 2025-01-23 23:18:48 -05:00
🐛 Fix many corner cases on custom font management.
This commit is contained in:
parent
6b1e5b4169
commit
43b34aa279
12 changed files with 562 additions and 324 deletions
|
@ -1,20 +1,43 @@
|
|||
CREATE TABLE team_font_variant (
|
||||
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
|
||||
team_id uuid NOT NULL REFERENCES team(id) ON DELETE CASCADE,
|
||||
profile_id uuid NULL REFERENCES profile(id) ON DELETE SET NULL,
|
||||
team_id uuid NOT NULL REFERENCES team(id) ON DELETE CASCADE DEFERRABLE,
|
||||
profile_id uuid NULL REFERENCES profile(id) ON DELETE SET NULL DEFERRABLE,
|
||||
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
modified_at timestamptz NOT NULL DEFAULT now(),
|
||||
deleted_at timestamptz NULL DEFAULT NULL,
|
||||
|
||||
font_id text NOT NULL,
|
||||
font_id uuid NOT NULL,
|
||||
font_family text NOT NULL,
|
||||
font_weight smallint NOT NULL,
|
||||
font_style text NOT NULL,
|
||||
|
||||
otf_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL,
|
||||
ttf_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL,
|
||||
woff1_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL,
|
||||
woff2_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL
|
||||
otf_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL DEFERRABLE,
|
||||
ttf_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL DEFERRABLE,
|
||||
woff1_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL DEFERRABLE,
|
||||
woff2_file_id uuid NULL REFERENCES storage_object(id) ON DELETE SET NULL DEFERRABLE
|
||||
);
|
||||
|
||||
CREATE INDEX team_font_variant_team_id_font_id_idx
|
||||
ON team_font_variant (team_id, font_id);
|
||||
|
||||
CREATE INDEX team_font_variant_profile_id_idx
|
||||
ON team_font_variant (profile_id);
|
||||
|
||||
CREATE INDEX team_font_variant_otf_file_id_idx
|
||||
ON team_font_variant (otf_file_id);
|
||||
|
||||
CREATE INDEX team_font_variant_ttf_file_id_idx
|
||||
ON team_font_variant (ttf_file_id);
|
||||
|
||||
CREATE INDEX team_font_variant_woff1_file_id_idx
|
||||
ON team_font_variant (woff1_file_id);
|
||||
|
||||
CREATE INDEX team_font_variant_woff2_file_id_idx
|
||||
ON team_font_variant (woff2_file_id);
|
||||
|
||||
ALTER TABLE team_font_variant
|
||||
ALTER COLUMN font_family SET STORAGE external,
|
||||
ALTER COLUMN font_style SET STORAGE external;
|
||||
|
||||
|
|
|
@ -16,20 +16,20 @@
|
|||
[app.util.services :as sv]
|
||||
[app.util.time :as dt]
|
||||
[app.worker :as wrk]
|
||||
[clojure.spec.alpha :as s]
|
||||
[cuerdas.core :as str]))
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
(declare create-font-variant)
|
||||
|
||||
(def valid-weight #{100 200 300 400 500 600 700 800 900 950})
|
||||
(def valid-style #{"normal" "italic"})
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::name ::us/not-empty-string)
|
||||
(s/def ::weight valid-weight)
|
||||
(s/def ::style valid-style)
|
||||
(s/def ::font-id (s/and ::us/string #(str/starts-with? % "custom-")))
|
||||
(s/def ::font-id ::us/uuid)
|
||||
(s/def ::content-type ::media/font-content-type)
|
||||
(s/def ::data (s/map-of ::us/string any?))
|
||||
|
||||
|
@ -76,29 +76,57 @@
|
|||
:otf-file-id (:id otf)
|
||||
:ttf-file-id (:id ttf)})))
|
||||
|
||||
;; --- UPDATE FONT VARIANT
|
||||
;; --- UPDATE FONT FAMILY
|
||||
|
||||
(s/def ::update-font-variant
|
||||
(s/keys :req-un [::profile-id ::team-id ::id ::font-family ::font-id]))
|
||||
(s/def ::update-font
|
||||
(s/keys :req-un [::profile-id ::team-id ::id ::name]))
|
||||
|
||||
(sv/defmethod ::update-font-variant
|
||||
[{:keys [pool] :as cfg} {:keys [id team-id profile-id font-family font-id] :as params}]
|
||||
(def sql:update-font
|
||||
"update team_font_variant
|
||||
set font_family = ?
|
||||
where team_id = ?
|
||||
and font_id = ?")
|
||||
|
||||
(sv/defmethod ::update-font
|
||||
[{:keys [pool] :as cfg} {:keys [team-id profile-id id name] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(teams/check-edition-permissions! conn profile-id team-id)
|
||||
(db/update! conn :team-font-variant
|
||||
{:font-family font-family
|
||||
:font-id font-id}
|
||||
{:id id
|
||||
:team-id team-id})
|
||||
(db/exec-one! conn [sql:update-font name team-id id])
|
||||
nil))
|
||||
|
||||
;; --- DELETE FONT
|
||||
|
||||
(s/def ::delete-font
|
||||
(s/keys :req-un [::profile-id ::team-id ::id]))
|
||||
|
||||
(sv/defmethod ::delete-font
|
||||
[{:keys [pool] :as cfg} {:keys [id team-id profile-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(teams/check-edition-permissions! conn profile-id team-id)
|
||||
|
||||
(let [items (db/query conn :team-font-variant
|
||||
{:font-id id :team-id team-id}
|
||||
{:for-update true})]
|
||||
(doseq [item items]
|
||||
;; Schedule object deletion
|
||||
(wrk/submit! {::wrk/task :delete-object
|
||||
::wrk/delay cf/deletion-delay
|
||||
::wrk/conn conn
|
||||
:id (:id item)
|
||||
:type :team-font-variant}))
|
||||
|
||||
(db/update! conn :team-font-variant
|
||||
{:deleted-at (dt/now)}
|
||||
{:font-id id :team-id team-id})
|
||||
nil)))
|
||||
|
||||
;; --- DELETE FONT VARIANT
|
||||
|
||||
(s/def ::delete-font-variant
|
||||
(s/keys :req-un [::profile-id ::team-id ::id]))
|
||||
|
||||
(sv/defmethod ::delete-font-variant
|
||||
[{:keys [pool] :as cfg} {:keys [id team-id profile-id font-family font-id] :as params}]
|
||||
[{:keys [pool] :as cfg} {:keys [id team-id profile-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(teams/check-edition-permissions! conn profile-id team-id)
|
||||
|
||||
|
@ -111,6 +139,5 @@
|
|||
|
||||
(db/update! conn :team-font-variant
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id
|
||||
:team-id team-id})
|
||||
{:id id :team-id team-id})
|
||||
nil))
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
(let [prof (th/create-profile* 1 {:is-active true})
|
||||
team-id (:default-team-id prof)
|
||||
proj-id (:default-project-id prof)
|
||||
font-id (uuid/custom 10 1)
|
||||
|
||||
ttfdata (-> (io/resource "app/tests/_files/font-1.ttf")
|
||||
(fs/slurp-bytes))
|
||||
|
@ -29,7 +30,7 @@
|
|||
params {::th/type :create-font-variant
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id
|
||||
:font-id "custom-somefont"
|
||||
:font-id font-id
|
||||
:font-family "somefont"
|
||||
:font-weight 400
|
||||
:font-style "normal"
|
||||
|
@ -56,6 +57,7 @@
|
|||
(let [prof (th/create-profile* 1 {:is-active true})
|
||||
team-id (:default-team-id prof)
|
||||
proj-id (:default-project-id prof)
|
||||
font-id (uuid/custom 10 1)
|
||||
|
||||
data (-> (io/resource "app/tests/_files/font-1.woff")
|
||||
(fs/slurp-bytes))
|
||||
|
@ -63,7 +65,7 @@
|
|||
params {::th/type :create-font-variant
|
||||
:profile-id (:id prof)
|
||||
:team-id team-id
|
||||
:font-id "custom-somefont"
|
||||
:font-id font-id
|
||||
:font-family "somefont"
|
||||
:font-weight 400
|
||||
:font-style "normal"
|
||||
|
|
|
@ -69,17 +69,17 @@
|
|||
(defn parse-font-weight
|
||||
[variant]
|
||||
(cond
|
||||
(re-seq #"(?i)(?:hairline|thin)" variant) 100
|
||||
(re-seq #"(?i)(?:extra light|ultra light)" variant) 200
|
||||
(re-seq #"(?i)(?:light)" variant) 300
|
||||
(re-seq #"(?i)(?:normal|regular)" variant) 400
|
||||
(re-seq #"(?i)(?:medium)" variant) 500
|
||||
(re-seq #"(?i)(?:semi bold|demi bold)" variant) 600
|
||||
(re-seq #"(?i)(?:bold)" variant) 700
|
||||
(re-seq #"(?i)(?:extra bold|ultra bold)" variant) 800
|
||||
(re-seq #"(?i)(?:black|heavy)" variant) 900
|
||||
(re-seq #"(?i)(?:extra black|ultra black)" variant) 950
|
||||
:else 400))
|
||||
(re-seq #"(?i)(?:hairline|thin)" variant) 100
|
||||
(re-seq #"(?i)(?:extra\s*light|ultra\s*light)" variant) 200
|
||||
(re-seq #"(?i)(?:light)" variant) 300
|
||||
(re-seq #"(?i)(?:normal|regular)" variant) 400
|
||||
(re-seq #"(?i)(?:medium)" variant) 500
|
||||
(re-seq #"(?i)(?:semi\s*bold|demi\s*bold)" variant) 600
|
||||
(re-seq #"(?i)(?:extra\s*bold|ultra\s*bold)" variant) 800
|
||||
(re-seq #"(?i)(?:bold)" variant) 700
|
||||
(re-seq #"(?i)(?:extra\s*black|ultra\s*black)" variant) 950
|
||||
(re-seq #"(?i)(?:black|heavy)" variant) 900
|
||||
:else 400))
|
||||
|
||||
(defn parse-font-style
|
||||
[variant]
|
||||
|
|
|
@ -30,8 +30,13 @@
|
|||
align-items: center;
|
||||
padding: 0px $big;
|
||||
|
||||
> div {
|
||||
width: 30%;
|
||||
> .family {
|
||||
min-width: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
> .variants {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
|
@ -50,20 +55,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
.fonts-group {
|
||||
margin-top: $big;
|
||||
}
|
||||
|
||||
.font-item {
|
||||
margin-top: $big;
|
||||
color: $color-gray-40;
|
||||
font-size: $fs14;
|
||||
background-color: $color-white;
|
||||
display: flex;
|
||||
min-width: 1000px;
|
||||
width: 100%;
|
||||
height: 97px;
|
||||
min-height: 97px;
|
||||
align-items: center;
|
||||
padding: $big;
|
||||
justify-content: space-between;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid $color-gray-10;
|
||||
|
@ -77,14 +80,52 @@
|
|||
font-size: $fs12;
|
||||
}
|
||||
|
||||
> div {
|
||||
width: 30%;
|
||||
> .family {
|
||||
min-width: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.variant {
|
||||
font-size: $fs14;
|
||||
> .filenames {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
> .variants {
|
||||
font-size: $fs14;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-grow: 1;
|
||||
|
||||
.variant {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-left: 6px;
|
||||
align-items: center;
|
||||
svg {
|
||||
fill: transparent;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.icon svg {
|
||||
fill: $color-gray-30;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.filenames {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -117,7 +158,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.dashboard-fonts-upload {
|
||||
max-width: 1000px;
|
||||
width: 100%;
|
||||
|
@ -164,4 +204,31 @@
|
|||
color: $color-gray-40;
|
||||
}
|
||||
}
|
||||
|
||||
.fonts-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
max-width: 1000px;
|
||||
width: 100%;
|
||||
height: 161px;
|
||||
|
||||
border: 1px dashed $color-gray-20;
|
||||
margin-top: 16px;
|
||||
|
||||
|
||||
.icon {
|
||||
svg {
|
||||
fill: $color-gray-40;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
color: $color-gray-40;
|
||||
font-size: $fs14;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,94 +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) UXBOX Labs SL
|
||||
|
||||
(ns app.main.data.dashboard.fonts
|
||||
(:require
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.data :as d]
|
||||
[app.common.media :as cm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.time :as dt]
|
||||
[app.util.timers :as ts]
|
||||
[app.main.data.messages :as dm]
|
||||
[app.util.webapi :as wa]
|
||||
[app.util.object :as obj]
|
||||
[app.util.transit :as t]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(defn fetch-fonts
|
||||
[{:keys [id] :as team}]
|
||||
(ptk/reify ::fetch-fonts
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/query! :team-font-variants {:team-id id})
|
||||
(rx/map (fn [items]
|
||||
#(assoc % :dashboard-fonts (d/index-by :id items))))))))
|
||||
|
||||
(defn add-font
|
||||
[font]
|
||||
(ptk/reify ::add-font
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :dashboard-fonts assoc (:id font) font))))
|
||||
|
||||
|
||||
(defn update-font
|
||||
[{:keys [id font-family] :as font}]
|
||||
(ptk/reify ::update-font
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [font (assoc font :font-id (str "custom-" (str/slug font-family)))]
|
||||
(update state :dashboard-fonts assoc id font)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [font (get-in state [:dashboard-fonts id])]
|
||||
(->> (rp/mutation! :update-font-variant font)
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn delete-font
|
||||
[{:keys [id] :as font}]
|
||||
(ptk/reify ::delete-font
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :dashboard-fonts dissoc id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [params (select-keys font [:id :team-id])]
|
||||
(->> (rp/mutation! :delete-font-variant params)
|
||||
(rx/ignore))))))
|
||||
|
||||
;; (defn upload-font
|
||||
;; [{:keys [id] :as font}]
|
||||
;; (ptk/reify ::upload-font
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [{:keys [on-success on-error]
|
||||
;; :or {on-success identity
|
||||
;; on-error rx/throw}} (meta params)]
|
||||
;; (->> (rp/mutation! :create-font-variant font)
|
||||
;; (rx/tap on-success)
|
||||
;; (rx/catch on-error))))))
|
||||
|
||||
;; (defn add-font
|
||||
;; "Add fonts to the state in a pending to upload state."
|
||||
;; [font]
|
||||
;; (ptk/reify ::add-font
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [id (uuid/next)
|
||||
;; font (-> font
|
||||
;; (assoc :created-at (dt/now))
|
||||
;; (assoc :id id)
|
||||
;; (assoc :status :draft))]
|
||||
;; (js/console.log (clj->js font))
|
||||
;; (assoc-in state [:dashboard-fonts id] font)))))
|
|
@ -6,42 +6,68 @@
|
|||
|
||||
(ns app.main.data.fonts
|
||||
(:require
|
||||
["opentype.js" :as ot]
|
||||
[app.common.data :as d]
|
||||
[app.common.spec :as us]
|
||||
[app.common.media :as cm]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.logging :as log]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[app.util.webapi :as wa]
|
||||
[cuerdas.core :as str]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(defn prepare-font-variant
|
||||
[item]
|
||||
{:id (str (:font-style item) "-" (:font-weight item))
|
||||
:name (str (cm/font-weight->name (:font-weight item)) " "
|
||||
(str/capital (:font-style item)))
|
||||
:style (:font-style item)
|
||||
:weight (str (:font-weight item))
|
||||
::fonts/woff1-file-id (:woff1-file-id item)
|
||||
::fonts/woff2-file-id (:woff2-file-id item)
|
||||
::fonts/ttf-file-id (:ttf-file-id item)
|
||||
::fonts/otf-file-id (:otf-file-id item)})
|
||||
|
||||
(defn prepare-font
|
||||
[[id [item :as items]]]
|
||||
{:id id
|
||||
:name (:font-family item)
|
||||
:family (:font-family item)
|
||||
:variants (mapv prepare-font-variant items)})
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; General purpose events & IMPL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn team-fonts-loaded
|
||||
[fonts]
|
||||
(ptk/reify ::team-fonts-loaded
|
||||
ptk/EffectEvent
|
||||
(effect [_ state stream]
|
||||
(let [fonts (->> (group-by :font-id fonts)
|
||||
(mapv prepare-font))]
|
||||
(fonts/register! :custom fonts)))))
|
||||
(letfn [;; Prepare font to the internal font database format.
|
||||
(prepare-font [[id [item :as items]]]
|
||||
{:id id
|
||||
:name (:font-family item)
|
||||
:family (:font-family item)
|
||||
:variants (->> items
|
||||
(map prepare-font-variant)
|
||||
(sort-by variant-sort-fn)
|
||||
(vec))})
|
||||
|
||||
(variant-sort-fn [item]
|
||||
[(:weight item)
|
||||
(if (= "normal" (:style item)) 1 2)])
|
||||
|
||||
(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)))))
|
||||
:style (:font-style item)
|
||||
:weight (str (:font-weight item))
|
||||
::fonts/woff1-file-id (:woff1-file-id item)
|
||||
::fonts/woff2-file-id (:woff2-file-id item)
|
||||
::fonts/ttf-file-id (:ttf-file-id item)
|
||||
::fonts/otf-file-id (:otf-file-id item)})
|
||||
|
||||
(adapt-font-id [variant]
|
||||
(update variant :font-id #(str "custom-" %)))]
|
||||
|
||||
(ptk/reify ::team-fonts-loaded
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc state :dashboard-fonts (d/index-by :id fonts)))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state stream]
|
||||
(let [fonts (->> fonts
|
||||
(map adapt-font-id)
|
||||
(group-by :font-id)
|
||||
(mapv prepare-font))]
|
||||
(fonts/register! :custom fonts))))))
|
||||
|
||||
(defn load-team-fonts
|
||||
[team-id]
|
||||
|
@ -51,7 +77,168 @@
|
|||
(->> (rp/query :team-font-variants {:team-id team-id})
|
||||
(rx/map team-fonts-loaded)))))
|
||||
|
||||
(defn process-upload
|
||||
"Given a seq of blobs and the team id, creates a ready-to-use fonts
|
||||
map with temporal ID's associated to each font entry."
|
||||
[blobs team-id]
|
||||
(letfn [(prepare [{:keys [font type name data] :as params}]
|
||||
(let [family (or (.getEnglishName ^js font "preferredFamily")
|
||||
(.getEnglishName ^js font "fontFamily"))
|
||||
variant (or (.getEnglishName ^js font "preferredSubfamily")
|
||||
(.getEnglishName ^js font "fontSubfamily"))]
|
||||
{:content {:data (js/Uint8Array. data)
|
||||
:name name
|
||||
:type type}
|
||||
:font-family family
|
||||
:font-weight (cm/parse-font-weight variant)
|
||||
:font-style (cm/parse-font-style variant)}))
|
||||
|
||||
(defn get-fonts
|
||||
[backend]
|
||||
(get @fonts/fonts backend []))
|
||||
(join [res {:keys [content] :as font}]
|
||||
(let [key-fn (juxt :font-family :font-weight :font-style)
|
||||
existing (d/seek #(= (key-fn font) (key-fn %)) (vals res))]
|
||||
(if existing
|
||||
(update res
|
||||
(:id existing)
|
||||
(fn [existing]
|
||||
(-> existing
|
||||
(update :data assoc (:type content) (:data content))
|
||||
(update :names conj (:name content)))))
|
||||
(let [tmp-id (uuid/next)]
|
||||
(assoc res tmp-id
|
||||
(-> font
|
||||
(assoc :id tmp-id)
|
||||
(assoc :team-id team-id)
|
||||
(assoc :names #{(:name content)})
|
||||
(assoc :data {(:type content)
|
||||
(:data content)})
|
||||
(dissoc :content)))))))
|
||||
|
||||
(parse-mtype [mtype]
|
||||
(case mtype
|
||||
"application/vnd.oasis.opendocument.formula-template" "font/otf"
|
||||
mtype))
|
||||
|
||||
(parse-font [{:keys [data] :as params}]
|
||||
(try
|
||||
(assoc params :font (ot/parse data))
|
||||
(catch :default e
|
||||
(log/warn :msg (str/fmt "skiping file %s, unsupported format" (:name params)))
|
||||
nil)))
|
||||
|
||||
(read-blob [blob]
|
||||
(->> (wa/read-file-as-array-buffer blob)
|
||||
(rx/map (fn [data]
|
||||
{:data data
|
||||
:name (.-name blob)
|
||||
:type (parse-mtype (.-type blob))}))))]
|
||||
|
||||
(->> (rx/from blobs)
|
||||
(rx/mapcat read-blob)
|
||||
(rx/map parse-font)
|
||||
(rx/filter some?)
|
||||
(rx/map prepare)
|
||||
(rx/reduce join {}))))
|
||||
|
||||
(defn- calculate-family-to-id-mapping
|
||||
[existing]
|
||||
(reduce #(assoc %1 (:font-family %2) (:font-id %2)) {} (vals existing)))
|
||||
|
||||
(defn merge-and-group-fonts
|
||||
"Function responsible to merge (and apropriatelly group) incoming
|
||||
fonts (processed by `process-upload`) into existing fonts
|
||||
in local state, preserving correct font-id references."
|
||||
[current-fonts installed-fonts incoming-fonts]
|
||||
(loop [famdb (-> (merge current-fonts installed-fonts)
|
||||
(calculate-family-to-id-mapping))
|
||||
items (vals incoming-fonts)
|
||||
result current-fonts]
|
||||
(if-let [{:keys [id font-family] :as item} (first items)]
|
||||
(let [font-id (or (get famdb font-family)
|
||||
(uuid/next))
|
||||
font (assoc item :font-id font-id)]
|
||||
(recur (assoc famdb font-family font-id)
|
||||
(rest items)
|
||||
(assoc result id font)))
|
||||
result)))
|
||||
|
||||
(defn rename-and-regroup
|
||||
"Function responsible to rename a font in a local state and properly
|
||||
regroup it to the apropriate `font-id` having in account current
|
||||
fonts and installed fonts."
|
||||
[current-fonts id name installed-fonts]
|
||||
(let [famdb (-> (merge current-fonts installed-fonts)
|
||||
(calculate-family-to-id-mapping))
|
||||
font-id (or (get famdb name)
|
||||
(uuid/next))]
|
||||
(update current-fonts id (fn [font]
|
||||
(-> font
|
||||
(assoc :name name)
|
||||
(assoc :font-id font-id))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Dashboard related events
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn add-font
|
||||
[font]
|
||||
(ptk/reify ::add-font
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :dashboard-fonts assoc (:id font) font))))
|
||||
|
||||
(defn update-font
|
||||
[{:keys [id name] :as params}]
|
||||
(us/assert ::us/uuid id)
|
||||
(us/assert ::us/not-empty-string name)
|
||||
(ptk/reify ::update-font
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
;; Update all variants that has the same font-id with the new
|
||||
;; name in the local state.
|
||||
(update state :dashboard-fonts
|
||||
(fn [fonts]
|
||||
(d/mapm (fn [_ font]
|
||||
(cond-> font
|
||||
(= id (:font-id font))
|
||||
(assoc :font-family name)))
|
||||
fonts))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/mutation! :update-font {:id id :name name :team-id team-id})
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn delete-font
|
||||
"Delete all variants related to the provided `font-id`."
|
||||
[font-id]
|
||||
(us/assert ::us/uuid font-id)
|
||||
(ptk/reify ::delete-font
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :dashboard-fonts
|
||||
(fn [variants]
|
||||
(d/removem (fn [[id variant]]
|
||||
(= (:font-id variant) font-id)) variants))))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/mutation! :delete-font {:id font-id :team-id team-id})
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn delete-font-variant
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::delete-font-variants
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :dashboard-fonts
|
||||
(fn [variants]
|
||||
(d/removem (fn [[_ variant]]
|
||||
(= (:id variant) id))
|
||||
variants))))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/mutation! :delete-font-variant {:id id :team-id team-id})
|
||||
(rx/ignore))))))
|
||||
|
|
|
@ -54,10 +54,6 @@
|
|||
(vec)
|
||||
(reset! fonts))))
|
||||
|
||||
(defn- remove-fonts
|
||||
[db backend]
|
||||
(reduce-kv #(cond-> %1 (= backend (:backend %3)) (dissoc %2)) db db))
|
||||
|
||||
(defn register!
|
||||
[backend fonts]
|
||||
(swap! fontsdb
|
||||
|
@ -94,7 +90,6 @@
|
|||
(unchecked-set node "type" "text/css")
|
||||
node))
|
||||
|
||||
|
||||
(defn- create-style-element
|
||||
[css]
|
||||
(let [node (.createElement js/document "style")]
|
||||
|
@ -164,9 +159,9 @@
|
|||
url(%(otf-uri)s) format('otf');
|
||||
}")
|
||||
|
||||
(defn- font-id->uri
|
||||
[font-id]
|
||||
(str (u/join cf/public-uri "assets/by-id/" font-id)))
|
||||
(defn- asset-id->uri
|
||||
[asset-id]
|
||||
(str (u/join cf/public-uri "assets/by-id/" asset-id)))
|
||||
|
||||
(defn generate-custom-font-variant-css
|
||||
[family variant]
|
||||
|
@ -174,10 +169,10 @@
|
|||
{:family family
|
||||
:style (:style variant)
|
||||
:weight (:weight variant)
|
||||
:woff2-uri (font-id->uri (::woff2-file-id variant))
|
||||
:woff1-uri (font-id->uri (::woff1-file-id variant))
|
||||
:ttf-uri (font-id->uri (::ttf-file-id variant))
|
||||
:otf-uri (font-id->uri (::otf-file-id variant))}))
|
||||
:woff2-uri (asset-id->uri (::woff2-file-id variant))
|
||||
:woff1-uri (asset-id->uri (::woff1-file-id variant))
|
||||
:ttf-uri (asset-id->uri (::ttf-file-id variant))
|
||||
:otf-uri (asset-id->uri (::otf-file-id variant))}))
|
||||
|
||||
(defn- generate-custom-font-css
|
||||
[{:keys [family variants] :as font}]
|
||||
|
@ -188,7 +183,7 @@
|
|||
(defmethod load-font :custom
|
||||
[{:keys [id family variants ::on-loaded] :as font}]
|
||||
(when (exists? js/window)
|
||||
(js/console.log "[debug:fonts]: loading google font" id)
|
||||
(js/console.log "[debug:fonts]: loading custom font" id)
|
||||
(let [css (generate-custom-font-css font)]
|
||||
(add-font-css! css))))
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
|
||||
(ns app.main.ui.dashboard.fonts
|
||||
(:require
|
||||
["opentype.js" :as ot]
|
||||
[app.common.data :as d]
|
||||
[app.common.media :as cm]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.dashboard.fonts :as df]
|
||||
[app.main.data.fonts :as df]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.components.context-menu :refer [context-menu]]
|
||||
|
@ -64,56 +64,23 @@
|
|||
[:h1 (tr "labels.fonts")]]
|
||||
[:nav
|
||||
#_[:ul
|
||||
[:li {:class (when (= section :fonts) "active")}
|
||||
[:a {:on-click go-fonts} (tr "labels.custom-fonts")]]
|
||||
[:li {:class (when (= section :providers) "active")}
|
||||
[:a {:on-click go-providers} (tr "labels.font-providers")]]]]
|
||||
[:li {:class (when (= section :fonts) "active")}
|
||||
[:a {:on-click go-fonts} (tr "labels.custom-fonts")]]
|
||||
[:li {:class (when (= section :providers) "active")}
|
||||
[:a {:on-click go-providers} (tr "labels.font-providers")]]]]
|
||||
|
||||
[:div]]))
|
||||
|
||||
(defn- prepare-fonts
|
||||
[blobs]
|
||||
(letfn [(prepare [{:keys [font type name data] :as params}]
|
||||
(let [family (or (.getEnglishName ^js font "preferredFamily")
|
||||
(.getEnglishName ^js font "fontFamily"))
|
||||
variant (or (.getEnglishName ^js font "preferredSubfamily")
|
||||
(.getEnglishName ^js font "fontSubfamily"))]
|
||||
{:content {:data (js/Uint8Array. data)
|
||||
:name name
|
||||
:type type}
|
||||
:font-id (str "custom-" (str/slug family))
|
||||
:font-family family
|
||||
:font-weight (cm/parse-font-weight variant)
|
||||
:font-style (cm/parse-font-style variant)}))
|
||||
|
||||
(parse-mtype [mtype]
|
||||
(case mtype
|
||||
"application/vnd.oasis.opendocument.formula-template" "font/otf"
|
||||
mtype))
|
||||
|
||||
(parse-font [{:keys [data] :as params}]
|
||||
(try
|
||||
(assoc params :font (ot/parse data))
|
||||
(catch :default e
|
||||
(log/warn :msg (str/fmt "skiping file %s, unsupported format" (:name params)))
|
||||
nil)))
|
||||
|
||||
(read-blob [blob]
|
||||
(->> (wa/read-file-as-array-buffer blob)
|
||||
(rx/map (fn [data]
|
||||
{:data data
|
||||
:name (.-name blob)
|
||||
:type (parse-mtype (.-type blob))}))))]
|
||||
|
||||
(->> (rx/from blobs)
|
||||
(rx/mapcat read-blob)
|
||||
(rx/map parse-font)
|
||||
(rx/filter some?)
|
||||
(rx/map prepare))))
|
||||
(mf/defc font-variant-display-name
|
||||
[{:keys [variant]}]
|
||||
[:*
|
||||
[:span (cm/font-weight->name (:font-weight variant))]
|
||||
(when (not= "normal" (:font-style variant))
|
||||
[:span " " (str/capital (:font-style variant))])])
|
||||
|
||||
(mf/defc fonts-upload
|
||||
[{:keys [team] :as props}]
|
||||
(let [fonts (mf/use-state {})
|
||||
[{:keys [team installed-fonts] :as props}]
|
||||
(let [fonts (mf/use-state {})
|
||||
input-ref (mf/use-ref)
|
||||
|
||||
uploading (mf/use-state #{})
|
||||
|
@ -126,19 +93,11 @@
|
|||
|
||||
on-selected
|
||||
(mf/use-callback
|
||||
(mf/deps team)
|
||||
(mf/deps team installed-fonts)
|
||||
(fn [blobs]
|
||||
(->> (prepare-fonts blobs)
|
||||
(rx/subs (fn [{:keys [content] :as font}]
|
||||
(let [key (font-key-fn font)]
|
||||
(swap! fonts update key
|
||||
(fn [val]
|
||||
(-> (or val font)
|
||||
(assoc :team-id (:id team))
|
||||
(update :id #(or % (uuid/next)))
|
||||
(update :data assoc (:type content) (:data content))
|
||||
(update :names (fnil conj #{}) (:name content))
|
||||
(dissoc :content))))))
|
||||
(->> (df/process-upload blobs (:id team))
|
||||
(rx/subs (fn [result]
|
||||
(swap! fonts df/merge-and-group-fonts installed-fonts result))
|
||||
(fn [error]
|
||||
(js/console.error "error" error))))))
|
||||
|
||||
|
@ -146,22 +105,26 @@
|
|||
(mf/use-callback
|
||||
(mf/deps team)
|
||||
(fn [item]
|
||||
(let [key (font-key-fn item)]
|
||||
(swap! uploading conj (:id item))
|
||||
(->> (rp/mutation! :create-font-variant item)
|
||||
(rx/delay-at-least 2000)
|
||||
(rx/subs (fn [font]
|
||||
(swap! fonts dissoc key)
|
||||
(swap! uploading disj (:id item))
|
||||
(st/emit! (df/add-font font)))
|
||||
(fn [error]
|
||||
(js/console.log "error" error)))))))
|
||||
(swap! uploading conj (:id item))
|
||||
(->> (rp/mutation! :create-font-variant item)
|
||||
(rx/delay-at-least 2000)
|
||||
(rx/subs (fn [font]
|
||||
(swap! fonts dissoc (:id item))
|
||||
(swap! uploading disj (:id item))
|
||||
(st/emit! (df/add-font font)))
|
||||
(fn [error]
|
||||
(js/console.log "error" error))))))
|
||||
|
||||
on-blur-name
|
||||
(fn [id event]
|
||||
(let [name (dom/get-target-val event)]
|
||||
(swap! fonts df/rename-and-regroup id name installed-fonts)))
|
||||
|
||||
on-delete
|
||||
(mf/use-callback
|
||||
(mf/deps team)
|
||||
(fn [item]
|
||||
(swap! fonts dissoc (font-key-fn item))))]
|
||||
(fn [{:keys [id] :as item}]
|
||||
(swap! fonts dissoc id)))]
|
||||
|
||||
[:div.dashboard-fonts-upload
|
||||
[:div.dashboard-fonts-hero
|
||||
|
@ -177,7 +140,7 @@
|
|||
|
||||
[:div.btn-primary
|
||||
{:on-click on-click}
|
||||
[:span "Add custom font"]
|
||||
[:span (tr "labels.add-custom-font")]
|
||||
[:& file-uploader {:input-id "font-upload"
|
||||
:accept cm/str-font-types
|
||||
:multi true
|
||||
|
@ -190,11 +153,11 @@
|
|||
[:div.font-item.table-row {:key (:id item)}
|
||||
[:div.table-field.family
|
||||
[:input {:type "text"
|
||||
:on-blur #(on-blur-name (:id item) %)
|
||||
:default-value (:font-family item)}]]
|
||||
[:div.table-field.variant
|
||||
[:span (cm/font-weight->name (:font-weight item))]
|
||||
(when (not= "normal" (:font-style item))
|
||||
[:span " " (str/capital (:font-style item))])]
|
||||
[:div.table-field.variants
|
||||
[:span.label
|
||||
[:& font-variant-display-name {:variant item}]]]
|
||||
[:div.table-field.filenames
|
||||
(for [item (:names item)]
|
||||
[:span item])]
|
||||
|
@ -210,56 +173,67 @@
|
|||
[:span.icon.close {:on-click #(on-delete item)} i/close]]]))]]))
|
||||
|
||||
(mf/defc installed-font
|
||||
[{:keys [font] :as props}]
|
||||
(let [open-menu? (mf/use-state false)
|
||||
[{:keys [font-id variants] :as props}]
|
||||
(let [font (first variants)
|
||||
|
||||
variants (sort-by (fn [item]
|
||||
[(:font-weight item)
|
||||
(if (= "normal" (:font-style item)) 1 2)])
|
||||
variants)
|
||||
|
||||
open-menu? (mf/use-state false)
|
||||
edit? (mf/use-state false)
|
||||
state (mf/use-var (:font-family font))
|
||||
|
||||
on-change
|
||||
(mf/use-callback
|
||||
(mf/deps font)
|
||||
(fn [event]
|
||||
(reset! state (dom/get-target-val event))))
|
||||
(fn [event]
|
||||
(reset! state (dom/get-target-val event)))
|
||||
|
||||
on-save
|
||||
(mf/use-callback
|
||||
(mf/deps font)
|
||||
(fn [event]
|
||||
(let [font (assoc font :font-family @state)]
|
||||
(st/emit! (df/update-font font))
|
||||
(reset! edit? false))))
|
||||
(fn [event]
|
||||
(let [font-family @state]
|
||||
(st/emit! (df/update-font
|
||||
{:id font-id
|
||||
:name font-family}))
|
||||
(reset! edit? false)))
|
||||
|
||||
on-key-down
|
||||
(mf/use-callback
|
||||
(mf/deps font)
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(on-save event))))
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(on-save event)))
|
||||
|
||||
on-cancel
|
||||
(mf/use-callback
|
||||
(mf/deps font)
|
||||
(fn [event]
|
||||
(reset! edit? false)
|
||||
(reset! state (:font-family font))))
|
||||
(fn [event]
|
||||
(reset! edit? false)
|
||||
(reset! state (:font-family font)))
|
||||
|
||||
delete-fn
|
||||
(mf/use-callback
|
||||
(mf/deps font)
|
||||
(st/emitf (df/delete-font font)))
|
||||
delete-font-fn
|
||||
(fn [] (st/emit! (df/delete-font font-id)))
|
||||
|
||||
delete-variant-fn
|
||||
(fn [id] (st/emit! (df/delete-font-variant id)))
|
||||
|
||||
on-delete
|
||||
(mf/use-callback
|
||||
(mf/deps font)
|
||||
(st/emitf (modal/show
|
||||
{:type :confirm
|
||||
:title (tr "modals.delete-font.title")
|
||||
:message (tr "modals.delete-font.message")
|
||||
:accept-label (tr "labels.delete")
|
||||
:on-accept delete-fn})))]
|
||||
(fn []
|
||||
(st/emit! (modal/show
|
||||
{:type :confirm
|
||||
:title (tr "modals.delete-font.title")
|
||||
:message (tr "modals.delete-font.message")
|
||||
:accept-label (tr "labels.delete")
|
||||
:on-accept (fn [props]
|
||||
(delete-font-fn))})))
|
||||
|
||||
on-delete-variant
|
||||
(fn [id]
|
||||
(st/emit! (modal/show
|
||||
{:type :confirm
|
||||
:title (tr "modals.delete-font-variant.title")
|
||||
:message (tr "modals.delete-font-variant.message")
|
||||
:accept-label (tr "labels.delete")
|
||||
:on-accept (fn [props]
|
||||
(delete-variant-fn id))})))]
|
||||
|
||||
[:div.font-item.table-row {:key (:id font)}
|
||||
[:div.font-item.table-row
|
||||
[:div.table-field.family
|
||||
(if @edit?
|
||||
[:input {:type "text"
|
||||
|
@ -268,10 +242,14 @@
|
|||
:on-change on-change}]
|
||||
[:span (:font-family font)])]
|
||||
|
||||
[:div.table-field.variant
|
||||
[:span (cm/font-weight->name (:font-weight font))]
|
||||
(when (not= "normal" (:font-style font))
|
||||
[:span " " (str/capital (:font-style font))])]
|
||||
[:div.table-field.variants
|
||||
(for [item variants]
|
||||
[:div.variant
|
||||
[:span.label
|
||||
[:& font-variant-display-name {:variant item}]]
|
||||
[:span.icon.close
|
||||
{:on-click #(on-delete-variant (:id item))}
|
||||
i/plus]])]
|
||||
|
||||
[:div]
|
||||
|
||||
|
@ -281,7 +259,7 @@
|
|||
{:disabled (str/blank? @state)
|
||||
:on-click on-save
|
||||
:class (dom/classnames :btn-disabled (str/blank? @state))}
|
||||
"Save"]
|
||||
(tr "labels.save")]
|
||||
[:span.icon.close {:on-click on-cancel} i/close]]
|
||||
|
||||
[:div.table-field.options
|
||||
|
@ -313,41 +291,45 @@
|
|||
[:h3 (tr "labels.installed-fonts")]
|
||||
[:div.installed-fonts-header
|
||||
[:div.table-field.family (tr "labels.font-family")]
|
||||
[:div.table-field.variant (tr "labels.font-variant")]
|
||||
[:div.table-field.variants (tr "labels.font-variants")]
|
||||
[:div]
|
||||
[:div.table-field.search-input
|
||||
[:input {:placeholder (tr "labels.search-font")
|
||||
:default-value ""
|
||||
:on-change on-change
|
||||
}]]]
|
||||
(for [[font-id fonts] (->> fonts
|
||||
(filter matches?)
|
||||
(group-by :font-id))]
|
||||
[:div.fonts-group
|
||||
(for [font (sort-by (juxt :font-weight :font-style) fonts)]
|
||||
[:& installed-font {:key (:id font) :font font}])])]))
|
||||
|
||||
(cond
|
||||
(seq fonts)
|
||||
(for [[font-id variants] (->> (vals fonts)
|
||||
(filter matches?)
|
||||
(group-by :font-id))]
|
||||
[:& installed-font {:key (str font-id)
|
||||
:font-id font-id
|
||||
:variants variants}])
|
||||
|
||||
(nil? fonts)
|
||||
[:div.fonts-placeholder
|
||||
[:div.icon i/loader]
|
||||
[:div.label (tr "dashboard.loading-fonts")]]
|
||||
|
||||
:else
|
||||
[:div.fonts-placeholder
|
||||
[:div.icon i/text]
|
||||
[:div.label (tr "dashboard.fonts.empty-placeholder")]])]))
|
||||
|
||||
(mf/defc fonts-page
|
||||
[{:keys [team] :as props}]
|
||||
(let [fonts-map (mf/deref refs/dashboard-fonts)
|
||||
fonts (vals fonts-map)]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps team)
|
||||
(st/emitf (df/fetch-fonts team)))
|
||||
|
||||
(let [fonts (mf/deref refs/dashboard-fonts)]
|
||||
[:*
|
||||
[:& header {:team team :section :fonts}]
|
||||
[:section.dashboard-container.dashboard-fonts
|
||||
[:& fonts-upload {:team team}]
|
||||
[:& fonts-upload {:team team :installed-fonts fonts}]
|
||||
[:& installed-fonts {:team team :fonts fonts}]]]))
|
||||
|
||||
(when fonts
|
||||
[:& installed-fonts {:team team
|
||||
:fonts fonts}])]]))
|
||||
(mf/defc font-providers-page
|
||||
[{:keys [team] :as props}]
|
||||
[:*
|
||||
[:& header {:team team :section :providers}]
|
||||
[:section.dashboard-container
|
||||
[:span "hello world font providers"]]])
|
||||
[:span "font providers"]]])
|
||||
|
|
|
@ -310,7 +310,16 @@
|
|||
[:div.row-flex
|
||||
[:div.input-select.font-option
|
||||
{:on-click #(reset! open-selector? true)}
|
||||
(:name font)]]
|
||||
(cond
|
||||
(= :multiple font-id)
|
||||
"--"
|
||||
|
||||
(some? font)
|
||||
(:name font)
|
||||
|
||||
:else
|
||||
(tr "dashboard.fonts.deleted-placeholder"))]]
|
||||
|
||||
|
||||
[:div.row-flex
|
||||
(let [size-options [8 9 10 11 12 14 18 24 36 48 72]
|
||||
|
|
|
@ -206,6 +206,12 @@ msgstr "Duplicate %s files"
|
|||
msgid "dashboard.empty-files"
|
||||
msgstr "You still have no files here"
|
||||
|
||||
msgid "dashboard.fonts.deleted-placeholder"
|
||||
msgstr "Font deleted"
|
||||
|
||||
msgid "dashboard.fonts.empty-placeholder"
|
||||
msgstr "You still have no custom fonts installed."
|
||||
|
||||
#, markdown
|
||||
msgid "dashboard.fonts.hero-text1"
|
||||
msgstr ""
|
||||
|
@ -239,6 +245,9 @@ msgstr "Shared Libraries"
|
|||
msgid "dashboard.loading-files"
|
||||
msgstr "loading your files …"
|
||||
|
||||
msgid "dashboard.loading-fonts"
|
||||
msgstr "loading your fonts …"
|
||||
|
||||
#: src/app/main/ui/dashboard/project_menu.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.move-to"
|
||||
msgstr "Move to"
|
||||
|
@ -790,6 +799,9 @@ msgstr "You are seeing version %s"
|
|||
msgid "labels.accept"
|
||||
msgstr "Accept"
|
||||
|
||||
msgid "labels.add-custom-font"
|
||||
msgstr "Add custom font"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs, src/app/main/ui/dashboard/team.cljs, src/app/main/ui/dashboard/team.cljs
|
||||
msgid "labels.admin"
|
||||
msgstr "Admin"
|
||||
|
@ -891,8 +903,8 @@ msgstr "Font Family"
|
|||
msgid "labels.font-providers"
|
||||
msgstr "Font providers"
|
||||
|
||||
msgid "labels.font-variant"
|
||||
msgstr "Style"
|
||||
msgid "labels.font-variants"
|
||||
msgstr "Styles"
|
||||
|
||||
msgid "labels.fonts"
|
||||
msgstr "Fonts"
|
||||
|
@ -1189,6 +1201,14 @@ msgstr "Are you sure you want to delete %s files?"
|
|||
msgid "modals.delete-file-multi-confirm.title"
|
||||
msgstr "Deleting %s files"
|
||||
|
||||
msgid "modals.delete-font-variant.message"
|
||||
msgstr ""
|
||||
"Are you sure you want to delete this font style? It will not load if is "
|
||||
"used in a file."
|
||||
|
||||
msgid "modals.delete-font-variant.title"
|
||||
msgstr "Deleting font style"
|
||||
|
||||
msgid "modals.delete-font.message"
|
||||
msgstr ""
|
||||
"Are you sure you want to delete this font? It will not load if is used in a "
|
||||
|
|
|
@ -210,6 +210,12 @@ msgstr "Duplicar %s archivos"
|
|||
msgid "dashboard.empty-files"
|
||||
msgstr "Todavía no hay ningún archivo aquí"
|
||||
|
||||
msgid "dashboard.fonts.deleted-placeholder"
|
||||
msgstr "Fuente eliminada."
|
||||
|
||||
msgid "dashboard.fonts.empty-placeholder"
|
||||
msgstr "Aun no tienes fuentes personalizadas."
|
||||
|
||||
#, markdown
|
||||
msgid "dashboard.fonts.hero-text1"
|
||||
msgstr ""
|
||||
|
@ -243,6 +249,9 @@ msgstr "Bibliotecas Compartidas"
|
|||
msgid "dashboard.loading-files"
|
||||
msgstr "cargando tus ficheros …"
|
||||
|
||||
msgid "dashboard.loading-fonts"
|
||||
msgstr "cargando tus fuentes …"
|
||||
|
||||
#: src/app/main/ui/dashboard/project_menu.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
msgid "dashboard.move-to"
|
||||
msgstr "Mover a"
|
||||
|
@ -796,6 +805,9 @@ msgstr "Estás viendo la versión %s"
|
|||
msgid "labels.accept"
|
||||
msgstr "Aceptar"
|
||||
|
||||
msgid "labels.add-custom-font"
|
||||
msgstr "Añadir fuentes personalizada"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs, src/app/main/ui/dashboard/team.cljs, src/app/main/ui/dashboard/team.cljs
|
||||
msgid "labels.admin"
|
||||
msgstr "Administración"
|
||||
|
@ -893,8 +905,8 @@ msgstr "Familia de fuente"
|
|||
msgid "labels.font-providers"
|
||||
msgstr "Proveedores de fuentes"
|
||||
|
||||
msgid "labels.font-variant"
|
||||
msgstr "Estilo"
|
||||
msgid "labels.font-variants"
|
||||
msgstr "Estilos"
|
||||
|
||||
msgid "labels.fonts"
|
||||
msgstr "Fuentes"
|
||||
|
@ -1191,10 +1203,18 @@ msgstr "¿Seguro que quieres eliminar %s archivos?"
|
|||
msgid "modals.delete-file-multi-confirm.title"
|
||||
msgstr "Eliminando %s archivos"
|
||||
|
||||
msgid "modals.delete-font-variant.message"
|
||||
msgstr ""
|
||||
"Estas seguro de querer eliminar esta estilo de fuente? Dejara de cargar si "
|
||||
"es usada en algun fichero."
|
||||
|
||||
msgid "modals.delete-font-variant.title"
|
||||
msgstr "Eliminando estilo de fuente"
|
||||
|
||||
msgid "modals.delete-font.message"
|
||||
msgstr ""
|
||||
"Are you sure you want to delete this font? It will not load if is used in a "
|
||||
"file."
|
||||
"Estas seguro de querer eliminar esta fuente? Dejara de cargar si es usada "
|
||||
"en algun fichero."
|
||||
|
||||
msgid "modals.delete-font.title"
|
||||
msgstr "Eliminando fuente"
|
||||
|
|
Loading…
Add table
Reference in a new issue