diff --git a/.gitignore b/.gitignore
index e1545372ba..25bd27a638 100644
--- a/.gitignore
+++ b/.gitignore
@@ -87,6 +87,7 @@ celerybeat-schedule
.venv
venv/
ENV/
+envs/
# Spyder project settings
.spyderproject
@@ -103,3 +104,6 @@ ENV/
node_modules/
.vscode
+
+# vendored js/css
+vendor/
diff --git a/package.json b/package.json
index 0328fe0bb3..3ef482883d 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,13 @@
"webpack-watch-files-plugin": "^1.0.3"
},
"dependencies": {
+ "@fortawesome/fontawesome-free": "^5.13.0",
+ "@openfonts/lato_latin-ext": "^1.44.1",
+ "@openfonts/open-sans_all": "^1.44.1",
"bootstrap": "^4.4.1",
- "optimize-css-assets-webpack-plugin": "^5.0.3"
+ "jquery": "^3.5.0",
+ "mathjax": "2.7.5",
+ "optimize-css-assets-webpack-plugin": "^5.0.3",
+ "popper.js": "^1.16.0"
}
}
diff --git a/pydata_sphinx_theme/__init__.py b/pydata_sphinx_theme/__init__.py
index d2e0c30bd0..92677400a2 100644
--- a/pydata_sphinx_theme/__init__.py
+++ b/pydata_sphinx_theme/__init__.py
@@ -3,13 +3,24 @@
"""
import os
+import docutils
+
+import sphinx
+import sphinx.util.logging
from sphinx.errors import ExtensionError
from .bootstrap_html_translator import BootstrapHTML5Translator
-import docutils
__version__ = "0.2.2dev0"
+NAME = "pydata_sphinx_theme"
+
+at_least_sphinx_three = sphinx.__version__ >= "3.0.0"
+
+logger = sphinx.util.logging.getLogger(__name__)
+
+warned = {}
+
def add_toctree_functions(app, pagename, templatename, context, doctree):
"""Add functions so Jinja templates can add toctree objects.
@@ -167,6 +178,66 @@ def get_edit_url():
# -----------------------------------------------------------------------------
+def setup_cdn(app, pagename, templatename, context, doctree):
+ """hoist the `use_public_cdns` config value to the template context
+ """
+
+ use_public_cdns = app.config.use_public_cdns
+
+ context["use_public_cdns"] = use_public_cdns
+
+ if not has_default_mathjax_path(app):
+ return
+
+ if at_least_sphinx_three or use_public_cdns:
+ return
+
+ mathjax_path = app.config.mathjax_path
+
+ if not warned.get("mathjax_path"):
+ logger.warning(
+ "`use_public_cdns` is %s, but `mathjax_path` is configured,"
+ " probably by default, as:\n\n"
+ " %s\n\n"
+ "> upgrade to `sphinx >=3`, which supports event `priority`...\n"
+ "> or configure `mathjax_path` in `conf.py`, e.g.:\n\n"
+ " import %s\n"
+ " def setup(app):\n"
+ " app.config.use_public_cdns = False\n"
+ " app.config.mathjax_path = %s.get_mathjax_path()\n",
+ use_public_cdns,
+ mathjax_path,
+ NAME,
+ NAME,
+ type="configuration",
+ location=pagename,
+ )
+ warned["mathjax_path"] = True
+
+
+# -----------------------------------------------------------------------------
+
+
+def configure_mathjax(app, env):
+ if not app.config.use_public_cdns and has_default_mathjax_path(app):
+ app.config.mathjax_path = get_mathjax_path()
+
+
+# -----------------------------------------------------------------------------
+
+
+def has_default_mathjax_path(app):
+ if "mathjax_path" not in app.config:
+ return False
+
+ return app.config.mathjax_path == app.config.values["mathjax_path"][0]
+
+
+def get_mathjax_path():
+ """Return the locally-vendored MathJax path"""
+ return "vendor/mathjax/latest.js?config=TeX-AMS-MML_HTMLorMML"
+
+
def get_html_theme_path():
"""Return list of HTML theme paths."""
theme_path = os.path.abspath(os.path.dirname(__file__))
@@ -175,7 +246,7 @@ def get_html_theme_path():
def setup(app):
theme_path = get_html_theme_path()[0]
- app.add_html_theme("pydata_sphinx_theme", theme_path)
+ app.add_html_theme(NAME, theme_path)
app.set_translator("html", BootstrapHTML5Translator)
# Read the Docs uses ``readthedocs`` as the name of the build, and also
@@ -185,5 +256,11 @@ def setup(app):
app.set_translator("readthedocsdirhtml", BootstrapHTML5Translator, override=True)
app.connect("html-page-context", setup_edit_url)
app.connect("html-page-context", add_toctree_functions)
+ app.connect("html-page-context", setup_cdn)
+
+ app.add_config_value("use_public_cdns", True, "html")
+
+ if at_least_sphinx_three:
+ app.connect("env-updated", configure_mathjax, priority=-1)
return {"parallel_read_safe": True, "parallel_write_safe": True}
diff --git a/pydata_sphinx_theme/layout.html b/pydata_sphinx_theme/layout.html
index f3719e77be..31a723d068 100644
--- a/pydata_sphinx_theme/layout.html
+++ b/pydata_sphinx_theme/layout.html
@@ -12,8 +12,15 @@
{% endmacro %}
{%- block css %}
+ {% if use_public_cdns %}
-
+
+ {% else %}
+
+
+
+ {% endif %}
+
{{- css() }}
{%- endblock %}
@@ -21,9 +28,12 @@
-
+ {% if use_public_cdns %}
-
+
+ {% else %}
+
+ {% endif %}
{%- endblock %}
{# Silence the sidebar's, relbar's #}
@@ -93,4 +103,4 @@
{%- block footer %}
{%- include "footer.html" %}
-{%- endblock %}
\ No newline at end of file
+{%- endblock %}
diff --git a/pydata_sphinx_theme/static/css/index.css b/pydata_sphinx_theme/static/css/index.css
index eb00f75123..4e238e2e57 100644
--- a/pydata_sphinx_theme/static/css/index.css
+++ b/pydata_sphinx_theme/static/css/index.css
@@ -1,4 +1,4 @@
-@import url(https://fonts.googleapis.com/css?family=Open+Sans:400|Lato:400);/*!
+/*!
* Bootstrap v4.4.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
diff --git a/src/scss/index.scss b/src/scss/index.scss
index dbad77f578..f4906fe602 100644
--- a/src/scss/index.scss
+++ b/src/scss/index.scss
@@ -10,9 +10,6 @@ $container-max-widths: (
// Include core Bootstrap
@import '../../node_modules/bootstrap/scss/bootstrap';
-// Import custom fonts
-@import url('https://fonts.googleapis.com/css?family=Open+Sans:400|Lato:400');
-
@import './base';
@import './navbar';
@@ -83,8 +80,8 @@ table.field-list {
}
}
-/**
- * Styling for autosummary tables
+/**
+ * Styling for autosummary tables
*/
// The first column (with the signature) should not wrap
diff --git a/webpack.common.js b/webpack.common.js
index 6f3e60b59e..e462a2e3f6 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -1,5 +1,9 @@
-const path = require('path');
+const { resolve } = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
+const CopyPlugin = require('copy-webpack-plugin');
+
+const staticPath = resolve(__dirname, 'pydata_sphinx_theme/static');
+const vendor = resolve(staticPath, 'vendor');
module.exports = {
entry: {
@@ -7,7 +11,7 @@ module.exports = {
},
output: {
filename: 'js/[name].js?[hash]',
- path: path.resolve(__dirname, 'pydata_sphinx_theme/static'),
+ path: staticPath,
},
module: {
rules: [
@@ -40,5 +44,93 @@ module.exports = {
},
],
},
- plugins: [new CleanWebpackPlugin()],
+ plugins: [
+ new CleanWebpackPlugin(),
+ new CopyPlugin([
+ // bootstrap
+ {
+ // includes popper.js
+ context: './node_modules/bootstrap/dist/js/',
+ from: 'bootstrap.bundle.min.*',
+ to: resolve(vendor, 'bootstrap')
+ },
+ {
+ context: './node_modules/bootstrap/',
+ from: 'LICENSE',
+ to: resolve(vendor, 'bootstrap')
+ },
+ // fonts
+ {
+ context: './node_modules/@fortawesome/fontawesome-free/css',
+ from: 'all.min.css',
+ to: resolve(vendor, 'fontawesome', 'css')
+ },
+ {
+ context: './node_modules/@fortawesome/fontawesome-free',
+ from: 'webfonts',
+ to: resolve(vendor, 'fontawesome', 'webfonts')
+ },
+ {
+ context: './node_modules/@fortawesome/fontawesome-free',
+ from: 'LICENSE.txt',
+ to: resolve(vendor, 'fontawesome')
+ },
+ {
+ context: './node_modules/@openfonts/open-sans_all',
+ from: 'files/*-400*',
+ to: resolve(vendor, 'open-sans_all')
+ },
+ {
+ context: './node_modules/@openfonts/open-sans_all',
+ from: 'index.css',
+ to: resolve(vendor, 'open-sans_all')
+ },
+ {
+ context: './node_modules/@openfonts/open-sans_all',
+ from: 'LICENSE.md',
+ to: resolve(vendor, 'open-sans_all')
+ },
+ {
+ context: './node_modules/@openfonts/lato_latin-ext',
+ from: 'files/*-400*',
+ to: resolve(vendor, 'lato_latin-ext')
+ },
+ {
+ context: './node_modules/@openfonts/lato_latin-ext',
+ from: 'index.css',
+ to: resolve(vendor, 'lato_latin-ext')
+ },
+ {
+ context: './node_modules/@openfonts/lato_latin-ext',
+ from: 'LICENSE.md',
+ to: resolve(vendor, 'lato_latin-ext')
+ },
+ // mathjax
+ {
+ context: './node_modules/mathjax',
+ from: '*.js',
+ to: resolve(vendor, 'mathjax')
+ },
+ {
+ context: './node_modules/mathjax',
+ from: 'jax/output/HTML-CSS',
+ to: resolve(vendor, 'mathjax/jax/output/HTML-CSS')
+ },
+ {
+ context: './node_modules/mathjax',
+ from: 'fonts/HTML-CSS/TeX',
+ to: resolve(vendor, 'mathjax/fonts/HTML-CSS/TeX')
+ },
+ {
+ context: './node_modules/mathjax',
+ from: 'config/TeX-AMS-MML_HTMLorMML.js',
+ to: resolve(vendor, 'mathjax/config')
+ },
+ {
+ context: './node_modules/mathjax',
+ from: 'LICENSE',
+ to: resolve(vendor, 'mathjax')
+ },
+ ])
+ ],
};
diff --git a/yarn.lock b/yarn.lock
index 84b97a21d8..9f071149c0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,21 @@
# yarn lockfile v1
+"@fortawesome/fontawesome-free@^5.13.0":
+ version "5.13.0"
+ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.0.tgz#fcb113d1aca4b471b709e8c9c168674fbd6e06d9"
+ integrity sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg==
+
+"@openfonts/lato_latin-ext@^1.44.1":
+ version "1.44.1"
+ resolved "https://registry.yarnpkg.com/@openfonts/lato_latin-ext/-/lato_latin-ext-1.44.1.tgz#b36a9c5905e0143f5f72e25cf635625f645603dd"
+ integrity sha512-uEhdHlTQtLumrWuKHV3JpzH7H1/gGnwXrNC8PAK6StF/Tq1AQPfdjokqgwrHPVQPooj/LAwujhvBwPDdW4/5eQ==
+
+"@openfonts/open-sans_all@^1.44.1":
+ version "1.44.1"
+ resolved "https://registry.yarnpkg.com/@openfonts/open-sans_all/-/open-sans_all-1.44.1.tgz#4a05c454a89d0a70eb2f17bfa2ea3f21e3aae091"
+ integrity sha512-/3uxdiRxH1Sk+llrw4o7lunFhM5IwU/LBo2PU6EYw+iMRNuoUqKU7eyeGtFdAbvErjsU9Xvbe75zkqmsBcXGaw==
+
"@types/anymatch@*":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
@@ -2895,6 +2910,11 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
+jquery@^3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.0.tgz#9980b97d9e4194611c36530e7dc46a58d7340fc9"
+ integrity sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ==
+
js-base64@^2.1.8:
version "2.5.2"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209"
@@ -3119,6 +3139,11 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
+mathjax@2.7.5:
+ version "2.7.5"
+ resolved "https://registry.yarnpkg.com/mathjax/-/mathjax-2.7.5.tgz#c9c5947f86f9be31651f5f3667d3c9a8bb01efe4"
+ integrity sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==
+
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -3919,6 +3944,11 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
+popper.js@^1.16.0:
+ version "1.16.1"
+ resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
+ integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
+
portfinder@^1.0.25:
version "1.0.25"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca"