2020-04-23 14:45:06 +02:00
|
|
|
;; 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/.
|
|
|
|
;;
|
|
|
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
|
|
|
;; defined by the Mozilla Public License, v. 2.0.
|
|
|
|
;;
|
|
|
|
;; Copyright (c) 2020 UXBOX Labs SL
|
|
|
|
|
|
|
|
(ns uxbox.main.fonts
|
|
|
|
"Fonts management and loading logic."
|
2020-04-23 16:09:22 +02:00
|
|
|
(:require-macros [uxbox.main.fonts :refer [preload-gfonts]])
|
2020-04-23 14:45:06 +02:00
|
|
|
(:require
|
|
|
|
[beicon.core :as rx]
|
2020-04-23 16:09:22 +02:00
|
|
|
[promesa.core :as p]
|
2020-04-23 14:45:06 +02:00
|
|
|
[okulary.core :as l]
|
|
|
|
[cuerdas.core :as str]
|
|
|
|
[uxbox.util.dom :as dom]
|
|
|
|
[uxbox.util.timers :as ts]
|
|
|
|
[uxbox.common.data :as d]
|
|
|
|
[clojure.set :as set]))
|
|
|
|
|
2020-04-23 16:09:22 +02:00
|
|
|
(def google-fonts
|
|
|
|
(preload-gfonts "fonts/gfonts.2020.04.23.json"))
|
|
|
|
|
2020-04-23 14:45:06 +02:00
|
|
|
(def local-fonts
|
|
|
|
[{:id "sourcesanspro"
|
|
|
|
:name "Source Sans Pro"
|
|
|
|
:family "sourcesanspro"
|
2020-04-28 13:24:53 +02:00
|
|
|
:variants [{:id "100" :name "100" :weight "100" :style "normal"}
|
|
|
|
{:id "100italic" :name "100 (italic)" :weight "100" :style "italic"}
|
|
|
|
{:id "200" :name "200" :weight "200" :style "normal"}
|
|
|
|
{:id "200italic" :name "200 (italic)" :weight "200" :style "italic"}
|
|
|
|
{:id "300" :name "300" :weight "300" :style "normal"}
|
|
|
|
{:id "300italic" :name "300 (italic)" :weight "300" :style "italic"}
|
|
|
|
{:id "regular" :name "regular" :weight "400" :style "normal"}
|
|
|
|
{:id "italic" :name "italic" :weight "400" :style "italic"}
|
|
|
|
{:id "500" :name "500" :weight "500" :style "normal"}
|
|
|
|
{:id "500italic" :name "500 (italic)" :weight "500" :style "italic"}
|
|
|
|
{:id "bold" :name "bold" :weight "bold" :style "normal"}
|
|
|
|
{:id "bolditalic" :name "bold (italic)" :weight "bold" :style "italic"}
|
|
|
|
{:id "black" :name "black" :weight "900" :style "normal"}
|
|
|
|
{:id "blackitalic" :name "black (italic)" :weight "900" :style "italic"}]}
|
2020-04-23 14:45:06 +02:00
|
|
|
{:id "roboto"
|
|
|
|
:family "roboto"
|
|
|
|
:name "Roboto"
|
2020-04-28 13:24:53 +02:00
|
|
|
:variants [{:id "100" :name "100" :weight "100" :style "normal"}
|
|
|
|
{:id "100italic" :name "100 (italic)" :weight "100" :style "italic"}
|
|
|
|
{:id "200" :name "200" :weight "200" :style "normal"}
|
|
|
|
{:id "200italic" :name "200 (italic)" :weight "200" :style "italic"}
|
|
|
|
{:id "regular" :name "regular" :weight "400" :style "normal"}
|
|
|
|
{:id "italic" :name "italic" :weight "400" :style "italic"}
|
|
|
|
{:id "500" :name "500" :weight "500" :style "normal"}
|
|
|
|
{:id "500italic" :name "500 (italic)" :weight "500" :style "italic"}
|
|
|
|
{:id "bold" :name "bold" :weight "bold" :style "normal"}
|
|
|
|
{:id "bolditalic" :name "bold (italic)" :weight "bold" :style "italic"}
|
|
|
|
{:id "black" :name "black" :weight "900" :style "normal"}
|
|
|
|
{:id "blackitalic" :name "black (italic)" :weight "900" :style "italic"}]}
|
2020-04-23 14:45:06 +02:00
|
|
|
{:id "robotocondensed"
|
|
|
|
:family "robotocondensed"
|
|
|
|
:name "Roboto Condensed"
|
2020-04-28 13:24:53 +02:00
|
|
|
:variants [{:id "100" :name "100" :weight "100" :style "normal"}
|
|
|
|
{:id "100italic" :name "100 (italic)" :weight "100" :style "italic"}
|
|
|
|
{:id "200" :name "200" :weight "200" :style "normal"}
|
|
|
|
{:id "200italic" :name "200 (italic)" :weight "200" :style "italic"}
|
|
|
|
{:id "regular" :name "regular" :weight "400" :style "normal"}
|
|
|
|
{:id "italic" :name "italic" :weight "400" :style "italic"}
|
|
|
|
{:id "500" :name "500" :weight "500" :style "normal"}
|
|
|
|
{:id "500italic" :name "500 (italic)" :weight "500" :style "italic"}
|
|
|
|
{:id "bold" :name "bold" :weight "bold" :style "normal"}
|
|
|
|
{:id "bolditalic" :name "bold (italic)" :weight "bold" :style "italic"}
|
|
|
|
{:id "black" :name "black" :weight "900" :style "normal"}
|
|
|
|
{:id "blackitalic" :name "black (italic)" :weight "900" :style "italic"}]}])
|
2020-04-23 14:45:06 +02:00
|
|
|
|
|
|
|
(defonce fontsdb (l/atom {}))
|
|
|
|
(defonce fontsview (l/atom {}))
|
|
|
|
|
|
|
|
(defn- materialize-fontsview
|
|
|
|
[db]
|
|
|
|
(reset! fontsview (reduce-kv (fn [acc k v]
|
|
|
|
(assoc acc k (sort-by :name v)))
|
|
|
|
{}
|
|
|
|
(group-by :backend (vals db)))))
|
|
|
|
(add-watch fontsdb "main"
|
|
|
|
(fn [_ _ _ db]
|
2020-04-30 17:16:10 +02:00
|
|
|
(ts/schedule #(materialize-fontsview db))))
|
2020-04-23 14:45:06 +02:00
|
|
|
|
|
|
|
(defn register!
|
|
|
|
[backend fonts]
|
|
|
|
(let [fonts (map #(assoc % :backend backend) fonts)]
|
|
|
|
(swap! fontsdb #(merge % (d/index-by :id fonts)))))
|
|
|
|
|
|
|
|
(register! :builtin local-fonts)
|
2020-04-23 16:09:22 +02:00
|
|
|
(register! :google google-fonts)
|
2020-04-23 14:45:06 +02:00
|
|
|
|
|
|
|
(defn resolve-variants
|
|
|
|
[id]
|
|
|
|
(get-in @fontsdb [id :variants]))
|
|
|
|
|
|
|
|
(defn resolve-fonts
|
|
|
|
[backend]
|
|
|
|
(get @fontsview backend))
|
|
|
|
|
|
|
|
|
|
|
|
;; --- Fonts Loader
|
|
|
|
|
|
|
|
(defonce loaded (l/atom #{}))
|
|
|
|
|
|
|
|
(defn- create-link-node
|
|
|
|
[uri]
|
|
|
|
(let [node (.createElement js/document "link")]
|
|
|
|
(unchecked-set node "href" uri)
|
|
|
|
(unchecked-set node "rel" "stylesheet")
|
|
|
|
(unchecked-set node "type" "text/css")
|
|
|
|
node))
|
|
|
|
|
|
|
|
(defmulti ^:private load-font :backend)
|
|
|
|
|
|
|
|
(defmethod load-font :builtin
|
2020-04-23 15:32:50 +02:00
|
|
|
[{:keys [id ::on-loaded] :as font}]
|
|
|
|
(js/console.log "[debug:fonts]: loading builtin font" id)
|
2020-04-23 16:09:22 +02:00
|
|
|
(when (fn? on-loaded)
|
|
|
|
(on-loaded id)))
|
2020-04-23 14:45:06 +02:00
|
|
|
|
|
|
|
(defmethod load-font :google
|
2020-04-23 15:32:50 +02:00
|
|
|
[{:keys [id family variants ::on-loaded] :as font}]
|
2020-05-05 19:48:51 +02:00
|
|
|
(when (exists? js/window)
|
|
|
|
(js/console.log "[debug:fonts]: loading google font" id)
|
|
|
|
(let [base (str "https://fonts.googleapis.com/css?family=" family)
|
|
|
|
variants (str/join "," (map :id variants))
|
|
|
|
uri (str base ":" variants "&display=block")
|
|
|
|
node (create-link-node uri)]
|
|
|
|
(.addEventListener node "load" (fn [event] (when (fn? on-loaded)
|
|
|
|
(on-loaded id))))
|
|
|
|
(.append (.-head js/document) node)
|
|
|
|
nil)))
|
2020-04-23 14:45:06 +02:00
|
|
|
|
|
|
|
(defmethod load-font :default
|
|
|
|
[{:keys [backend] :as font}]
|
|
|
|
(js/console.warn "no implementation found for" backend))
|
|
|
|
|
|
|
|
(defn ensure-loaded!
|
2020-04-23 15:32:50 +02:00
|
|
|
([id]
|
2020-04-23 16:09:22 +02:00
|
|
|
(p/create (fn [resolve]
|
|
|
|
(ensure-loaded! id resolve))))
|
2020-04-23 15:32:50 +02:00
|
|
|
([id on-loaded]
|
|
|
|
(if (contains? @loaded id)
|
|
|
|
(on-loaded id)
|
|
|
|
(when-let [font (get @fontsdb id)]
|
|
|
|
(load-font (assoc font ::on-loaded on-loaded))
|
|
|
|
(swap! loaded conj id)))))
|
|
|
|
|
2020-04-23 14:45:06 +02:00
|
|
|
|