Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make published html scripts configurable #11149

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 2 additions & 4 deletions deps/publishing/src/logseq/publishing.cljs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ns ^:node-only logseq.publishing
"This node only ns provides api fns for exporting a publishing app"
(:require [logseq.publishing.html :as publish-html]
[logseq.publishing.export :as publish-export]))
(:require [logseq.publishing.export :as publish-export]
[logseq.publishing.html :as publish-html]))

(defn- default-notification-fn [msg]
(if (= "error" (:type msg))
Expand All @@ -14,8 +14,6 @@ configuration is done through logseq/config.edn. There are a few explicit option
can be passed:
* :ui/theme - Theme mode that can either be 'light' or 'dark'.
* :ui/radix-color - Accent color. See available values in Settings.
* :html-options - A map of values that are inserted into index.html. Map keys
can be icon, name, alias, title, description and url
* :default-notification-fn - Configure how errors are reported when creating the export.
Default is to throw an exception when it occurs."
[db static-dir graph-dir output-dir {:keys [notification-fn dev?]
Expand Down
133 changes: 72 additions & 61 deletions deps/publishing/src/logseq/publishing/html.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"This frontend only ns builds the publishing html including doing all the
necessary db filtering"
(:require [clojure.string :as string]
[datascript.transit :as dt]
[goog.string :as gstring]
[goog.string.format]
[datascript.transit :as dt]
[logseq.publishing.db :as db]))

;; Copied from hiccup but tweaked for publish usage
Expand All @@ -22,26 +22,78 @@ necessary db filtering"
;; 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]]
(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)))
(when (some? v)
(gstring/format " %s=\"%s\"" (name k) v))) v))
(seq? v)
(string/join " " (map html v))
:else (str v)))

(def ^{:private boolean} spa-github-script
"// 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))")


(defn- construct-body [transit-db app-state scripts-before]
(into
[:body
[:div {:id "root"}]]
(into
(vec
(map (fn [{:keys [src,content]}]
[:script {:src src} (str content)]) scripts-before))
[[: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"} spa-github-script]
[:script {:src "static/js/react.production.min.js"}]
[:script {:src "static/js/react-dom.production.min.js"}]
[:script {:src "static/js/ui.js"}]
[: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/html2canvas.min.js"}]
[:script {:src "static/js/code-editor.js"}]
[:script {:src "static/js/custom.js"}]])))

(defn- ^:large-vars/html publishing-html
[transit-db app-state options]
(let [{:keys [icon name alias title description url]} options
CNLHC marked this conversation as resolved.
Show resolved Hide resolved
(let [{:keys [icon name alias title description url scripts-before]} options
icon (or icon "static/img/logo.png")
project (or alias name)]
(str "<!DOCTYPE html>\n"
Expand Down Expand Up @@ -88,54 +140,13 @@ necessary db filtering"
[: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/react.production.min.js"}]
[:script {:src "static/js/react-dom.production.min.js"}]
[:script {:src "static/js/ui.js"}]
[: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/html2canvas.min.js"}]
[:script {:src "static/js/code-editor.js"}]
[:script {:src "static/js/custom.js"}]])))))
(construct-body transit-db app-state scripts-before))))))


(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]}]
[db* {:keys [app-state repo-config]}]
(let [all-pages-public? (if-let [val (:publishing/all-pages-public? repo-config)]
val
(:all-pages-public? repo-config))
Expand All @@ -146,6 +157,6 @@ generated index.html string and assets used by the html"
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)]
raw-html-str (publishing-html db-str state (:publishing/html-options repo-config))]
{:html raw-html-str
:asset-filenames asset-filenames}))
15 changes: 15 additions & 0 deletions src/main/frontend/schema/handler/common_config.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@
"Schema that is common for global-config and repo-config"
(:require [malli.util :as mu]))

(def html-options
(mu/optional-keys
[:map
[:icon :string]
[:name :string]
[:alias :string]
[:title :string]
[:description :string]
[:url :string]
[:scripts-before
[:vector [:map
[:src {:optional true} :string
:content {:optional true} :string]]]]]))

(def Config-edn
(mu/optional-keys
[:map
Expand Down Expand Up @@ -29,6 +43,7 @@
[:export/bullet-indentation
[:enum :eight-spaces :four-spaces :two-spaces :tab]]
[:publishing/all-pages-public? :boolean]
[:publishing/html-options? html-options]
[:default-home [:map
[:page {:optional true} :string]
[:sidebar {:optional true} [:or :string [:vector :string]]]]]
Expand Down
19 changes: 19 additions & 0 deletions src/resources/templates/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,25 @@
;; Default value: false
;; :publishing/all-pages-public? false

;; Control published html content.
:publishing/html-options
{;;
;; Favicon url. Default to the logseq icon.
;; :icon ""
;; Content of og:site_name
;; :name ""
;; Content of og:title
;; :title ""
;; Content of og:description
;; :description ""
;; Content of og:url
;; :url ""
;;
;; Inject extra <scripts> tag to the generated index.html.
;; Example
;; :scripts-before [{:src "script_url" :content: "script content"}]
:scripts-before []}

;; Define the default home page and sidebar status.
;; If unspecified, the journal page will be loaded on startup and the right sidebar will stay hidden.
;; The `:page` value represents the name of the page displayed at startup.
Expand Down