mirror of
https://github.com/readthedocs/sphinx_rtd_theme.git
synced 2025-02-25 18:55:21 -06:00
Addons: integrate with new beta addons flyout (#1526)
* Addons: integrate with new beta addons flyout Initial experimentation to use the `CustomEvent` triggered by the addons called `readthedocsdataready` event (from https://github.com/readthedocs/addons/pull/64/) to build the Read the Docs flyout being integrated into the theme keeping the original look & feel. * Related: https://github.com/readthedocs/addons/pull/64/ * Closes #1523 * `READTHEDOCS` variable has to be passed to the `html_context` This is because we are not executing the Read the Docs magic that modifies the `conf.py` file on the fly :/ * Update code to match the latest changes * Use `.join` to avoid rendering the Array with `,` * Update code to use the v1 API structure response * Don't auto-remove the original flyout This can be disabled per-project by using the settings UI from the dashboard. * Join the values to avoid strange `,`s * Support translations Use the current pattern to translate string generated for the flyout. * Remove HTML tags for testing * Show "Search" section on flyout * Render footer * Add some styling * TODO comments to work on * add `div.injected` * Apply suggestions from code review Co-authored-by: Anthony <aj@ohess.org> * Translate privacy policy * Add `.rtd-current-item` class to selected version/language * Refactor code to show sections only if there is content * Epub instead of EPUB for backward compatibility * Show the modal when clicking on the "Search docs" from navbar * Remove privacy policy link from flyout * Add UTM analytics * Move CSS style into SASS file * Move the `script` tag into its own file * Rename JS file to mark it as a Sphinx template * Build css/js files Run `npm ci` and `npm run build` using NodeJS 14.20.1. * Add the JS template in the package --------- Co-authored-by: Anthony <aj@ohess.org>
This commit is contained in:
parent
28c377f99a
commit
357e76dc42
@ -7,6 +7,7 @@ recursive-include sphinx_rtd_theme *.css
|
||||
recursive-include sphinx_rtd_theme *.eot
|
||||
recursive-include sphinx_rtd_theme *.html
|
||||
recursive-include sphinx_rtd_theme *.js
|
||||
recursive-include sphinx_rtd_theme *.js_t
|
||||
recursive-include sphinx_rtd_theme *.svg
|
||||
recursive-include sphinx_rtd_theme *.ttf
|
||||
recursive-include sphinx_rtd_theme *.woff
|
||||
|
@ -68,6 +68,10 @@ if not 'READTHEDOCS' in os.environ:
|
||||
range(1, 100)
|
||||
))
|
||||
|
||||
if 'READTHEDOCS' in os.environ:
|
||||
html_context['READTHEDOCS'] = True
|
||||
html_context['READTHEDOCS_PROJECT'] = os.environ.get("READTHEDOCS_PROJECT")
|
||||
|
||||
html_logo = "demo/static/logo-wordmark-light.svg"
|
||||
html_show_sourcelink = True
|
||||
html_favicon = "demo/static/favicon.ico"
|
||||
|
@ -16,6 +16,9 @@
|
||||
<html class="writer-html5" lang="{{ lang_attr }}"{% if sphinx_version_info >= (7, 2) %} data-content_root="{{ content_root }}"{% endif %}>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
{%- if READTHEDOCS and not embedded %}
|
||||
<meta name="readthedocs-addons-api-version" content="1">
|
||||
{%- endif %}
|
||||
{{- metatags }}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
{%- block htmltitle %}
|
||||
@ -64,6 +67,10 @@
|
||||
{%- endfor %}
|
||||
<script src="{{ pathto('_static/js/theme.js', 1) }}"></script>
|
||||
|
||||
{%- if READTHEDOCS %}
|
||||
<script src="{{ pathto('_static/js/versions.js', 1) }}"></script>
|
||||
{%- endif %}
|
||||
|
||||
{#- OPENSEARCH #}
|
||||
{%- if use_opensearch %}
|
||||
<link rel="search" type="application/opensearchdescription+xml"
|
||||
|
@ -1 +1 @@
|
||||
.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
|
||||
.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions .rst-other-versions .rtd-current-item{font-weight:700}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}#flyout-search-form{padding:6px}
|
File diff suppressed because one or more lines are too long
125
sphinx_rtd_theme/static/js/versions.js_t
Normal file
125
sphinx_rtd_theme/static/js/versions.js_t
Normal file
@ -0,0 +1,125 @@
|
||||
function renderLanguages(config) {
|
||||
if (!config.projects.translations.length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const languagesHTML = `
|
||||
<dl>
|
||||
<dt>{{ _('Languages') }}</dt>
|
||||
${ config.projects.translations.map(
|
||||
(translation) => `
|
||||
<dd ${ translation.slug == config.projects.current.slug ? 'class="rtd-current-item"' : '' }>
|
||||
<a href="${ translation.urls.documentation }">${ translation.language.code }</a>
|
||||
</dd>
|
||||
`).join("\n")}
|
||||
</dl>
|
||||
`;
|
||||
return languagesHTML;
|
||||
}
|
||||
|
||||
function renderVersions(config) {
|
||||
if (!config.versions.active.length) {
|
||||
return "";
|
||||
}
|
||||
const versionsHTML = `
|
||||
<dl>
|
||||
<dt>{{ _('Versions') }}</dt>
|
||||
${ config.versions.active.map(
|
||||
(version) => `
|
||||
<dd ${ version.slug === config.versions.current.slug ? 'class="rtd-current-item"' : '' }>
|
||||
<a href="${ version.urls.documentation }">${ version.slug }</a>
|
||||
</dd>
|
||||
`).join("\n")}
|
||||
</dl>
|
||||
`;
|
||||
return versionsHTML;
|
||||
}
|
||||
|
||||
function renderDownloads(config) {
|
||||
if (!Object.keys(config.versions.current.downloads).length) {
|
||||
return "";
|
||||
}
|
||||
const downloadsNameDisplay = {
|
||||
pdf: "PDF",
|
||||
epub: "Epub",
|
||||
htmlzip: "HTML",
|
||||
};
|
||||
|
||||
const downloadsHTML = `
|
||||
<dl>
|
||||
<dt>{{ _('Downloads') }}</dt>
|
||||
${ Object.entries(config.versions.current.downloads).map(
|
||||
([name, url]) => `
|
||||
<dd>
|
||||
<a href="${ url }">${ downloadsNameDisplay[name] }</a>
|
||||
</dd>
|
||||
`).join("\n")}
|
||||
</dl>
|
||||
`;
|
||||
return downloadsHTML;
|
||||
}
|
||||
|
||||
document.addEventListener("readthedocs-addons-data-ready", function(event) {
|
||||
const config = event.detail.data();
|
||||
|
||||
const flyout = `
|
||||
<div class="rst-versions" data-toggle="rst-versions" role="note">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
<span class="fa fa-book"> Read the Docs</span>
|
||||
v: ${ config.versions.current.slug }
|
||||
<span class="fa fa-caret-down"></span>
|
||||
</span>
|
||||
<div class="rst-other-versions">
|
||||
<div class="injected">
|
||||
${ renderLanguages(config) }
|
||||
${ renderVersions(config) }
|
||||
${ renderDownloads(config) }
|
||||
<dl>
|
||||
<dt>{{ _('On Read the Docs') }}</dt>
|
||||
<dd>
|
||||
<a href="${ config.projects.current.urls.home }">{{ _('Project Home') }}</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="${ config.projects.current.urls.builds }">{{ _('Builds') }}</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="${ config.projects.current.urls.downloads }">{{ _('Downloads') }}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ _('Search') }}</dt>
|
||||
<dd>
|
||||
<form id="flyout-search-form">
|
||||
<input
|
||||
class="wy-form"
|
||||
type="text"
|
||||
name="q"
|
||||
aria-label="{{ _('Search docs') }}"
|
||||
placeholder="{{ _('Search docs') }}"
|
||||
/>
|
||||
</form>
|
||||
</dd>
|
||||
</dl>
|
||||
<hr />
|
||||
<small>
|
||||
<span>Hosted by <a href="https://about.readthedocs.org/?utm_source={{ READTHEDOCS_PROJECT }}&utm_content=flyout">Read the Docs</a></span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Inject the generated flyout into the body HTML element.
|
||||
document.body.insertAdjacentHTML("beforeend", flyout);
|
||||
|
||||
// Trigger the Read the Docs Addons Search modal when clicking on the "Search docs" input from inside the flyout.
|
||||
document.querySelector("#flyout-search-form").addEventListener("focusin", () => {
|
||||
const event = new CustomEvent("readthedocs-search-show");
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
// Trigger the Read the Docs Addons Search modal when clicking on "Search docs" input from the topnav.
|
||||
document.querySelector("[role='search'] input").addEventListener("focusin", () => {
|
||||
const event = new CustomEvent("readthedocs-search-show");
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
});
|
@ -1,34 +0,0 @@
|
||||
{% if READTHEDOCS %}
|
||||
{# Add rst-badge after rst-versions for small badge style. #}
|
||||
<div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="{{ _('Versions') }}">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
<span class="fa fa-book"> Read the Docs</span>
|
||||
v: {{ current_version }}
|
||||
<span class="fa fa-caret-down"></span>
|
||||
</span>
|
||||
<div class="rst-other-versions">
|
||||
<dl>
|
||||
<dt>{{ _('Versions') }}</dt>
|
||||
{% for slug, url in versions %}
|
||||
<dd><a href="{{ url }}">{{ slug }}</a></dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{ _('Downloads') }}</dt>
|
||||
{% for type, url in downloads %}
|
||||
<dd><a href="{{ url }}">{{ type }}</a></dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
<dl>
|
||||
{# Translators: The phrase "Read the Docs" is not translated #}
|
||||
<dt>{{ _('On Read the Docs') }}</dt>
|
||||
<dd>
|
||||
<a href="//{{ PRODUCTION_DOMAIN }}/projects/{{ slug }}/?fromdocs={{ slug }}">{{ _('Project Home') }}</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="//{{ PRODUCTION_DOMAIN }}/builds/{{ slug }}/?fromdocs={{ slug }}">{{ _('Builds') }}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
@ -58,6 +58,8 @@
|
||||
display: inline-block
|
||||
padding: $base-line-height / 4
|
||||
color: $section-background-color
|
||||
.rtd-current-item
|
||||
font-weight: bold
|
||||
&.rst-badge
|
||||
width: auto
|
||||
bottom: 20px
|
||||
@ -92,3 +94,6 @@
|
||||
display: none
|
||||
&.shift
|
||||
display: block
|
||||
|
||||
#flyout-search-form
|
||||
padding: 6px
|
||||
|
Loading…
Reference in New Issue
Block a user