/
html.cljs
147 lines (141 loc) · 6.32 KB
/
html.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
(ns logseq.publishing.html
"This frontend only ns builds the publishing html including doing all the
necessary db filtering"
(:require [clojure.string :as string]
[goog.string :as gstring]
[goog.string.format]
[datascript.transit :as dt]
[logseq.publishing.db :as db]))
;; Copied from hiccup but tweaked for publish usage
;; Any changes here should also be made in frontend.publishing/unescape-html
(defn- escape-html
"Change special characters into HTML character entities."
[text]
(-> text
(string/replace "&" "logseq____&")
(string/replace "<" "logseq____<")
(string/replace ">" "logseq____>")
(string/replace "\"" "logseq____"")
(string/replace "'" "logseq____'")))
;; Copied from https://github.com/babashka/babashka/blob/8c1077af00c818ade9e646dfe1297bbe24b17f4d/examples/notes.clj#L21
(defn- html [v]
(cond (vector? v)
(let [tag (first v)
attrs (second v)
attrs (when (map? attrs) attrs)
elts (if attrs (nnext v) (next v))
tag-name (name tag)]
(gstring/format "<%s%s>%s</%s>\n" tag-name (html attrs) (html elts) tag-name))
(map? v)
(string/join ""
(keep (fn [[k v]]
;; Skip nil values because some html tags haven't been
;; given values through html-options
(when (some? v)
(gstring/format " %s=\"%s\"" (name k) v))) v))
(seq? v)
(string/join " " (map html v))
:else (str v)))
(defn- ^:large-vars/html publishing-html
[transit-db app-state options]
(let [{:keys [icon name alias title description url]} options
icon (or icon "static/img/logo.png")
project (or alias name)]
(str "<!DOCTYPE html>\n"
(html
(list
[:head
[:meta {:charset "utf-8"}]
[:meta
{:content
"minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no",
:name "viewport"}]
[:link {:type "text/css", :href "static/css/tabler-icons.min.css", :rel "stylesheet"}]
[:link {:type "text/css", :href "static/css/style.css", :rel "stylesheet"}]
[:link {:type "text/css", :href "static/css/custom.css", :rel "stylesheet"}]
[:link {:type "text/css", :href "static/css/export.css", :rel "stylesheet"}]
[:link
{:href icon
:type "image/png",
:rel "shortcut icon"}]
[:link
{:href icon
:sizes "192x192",
:rel "shortcut icon"}]
[:link
{:href icon
:rel "apple-touch-icon"}]
[:meta {:name "apple-mobile-web-app-title" :content project}]
[:meta {:name "apple-mobile-web-app-capable" :content "yes"}]
[:meta {:name "apple-touch-fullscreen" :content "yes"}]
[:meta {:name "apple-mobile-web-app-status-bar-style" :content "black-translucent"}]
[:meta {:name "mobile-web-app-capable" :content "yes"}]
[:meta {:content title, :property "og:title"}]
[:meta {:content "site", :property "og:type"}]
(when url [:meta {:content url, :property "og:url"}])
[:meta
{:content icon
:property "og:image"}]
[:meta
{:content description
:property "og:description"}]
[:title title]
[:meta {:content project, :property "og:site_name"}]
[:meta
{:description description}]]
[:body
[:div {:id "root"}]
[:script (gstring/format "window.logseq_db=%s" (js/JSON.stringify (escape-html transit-db)))]
[:script (str "window.logseq_state=" (js/JSON.stringify (pr-str app-state)))]
[:script {:type "text/javascript"}
"// Single Page Apps for GitHub Pages
// https://github.com/rafgraph/spa-github-pages
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
// ----------------------------------------------------------------------
// This script checks to see if a redirect is present in the query string
// and converts it back into the correct url and adds it to the
// browser's history using window.history.replaceState(...),
// which won't cause the browser to attempt to load the new url.
// When the single page app is loaded further down in this file,
// the correct url will be waiting in the browser's history for
// the single page app to route accordingly.
(function(l) {
if (l.search) {
var q = {};
l.search.slice(1).split('&').forEach(function(v) {
var a = v.split('=');
q[a[0]] = a.slice(1).join('=').replace(/~and~/g, '&');
});
if (q.p !== undefined) {
window.history.replaceState(null, null,
l.pathname.slice(0, -1) + (q.p || '') +
(q.q ? ('?' + q.q) : '') +
l.hash
);
}
}
}(window.location))"]
;; TODO: should make this configurable
[:script {:src "static/js/main.js"}]
[:script {:src "static/js/interact.min.js"}]
[:script {:src "static/js/highlight.min.js"}]
[:script {:src "static/js/katex.min.js"}]
[:script {:src "static/js/code-editor.js"}]
[:script {:src "static/js/custom.js"}]])))))
(defn build-html
"Given the graph's db, filters the db using the given options and returns the
generated index.html string and assets used by the html"
[db* {:keys [app-state repo-config html-options]}]
(let [all-pages-public? (if-let [val (:publishing/all-pages-public? repo-config)]
val
(:all-pages-public? repo-config))
[db asset-filenames'] (if all-pages-public?
(db/clean-export! db*)
(db/filter-only-public-pages-and-blocks db*))
asset-filenames (remove nil? asset-filenames')
db-str (dt/write-transit-str db)
state (assoc app-state
:config {"local" repo-config})
raw-html-str (publishing-html db-str state html-options)]
{:html raw-html-str
:asset-filenames asset-filenames}))