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

Show version/language selectors below the title #1601

Merged
merged 31 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bac696e
Show version/language selectors below the title
humitos Sep 16, 2024
79a7c2e
Use CSS styles from old attempt
humitos Sep 16, 2024
c8be08d
Update CSS to apply to both selectors
humitos Sep 17, 2024
b819795
Prepend the current version if it's hidden
humitos Sep 17, 2024
e0d296c
Split it into two different configs
humitos Sep 17, 2024
232c288
Use correct value for language
humitos Sep 17, 2024
cee1b45
Make the selectors more prominent
humitos Sep 17, 2024
64305f8
Typo fix on comment
humitos Sep 17, 2024
218c418
Update CSS
humitos Sep 17, 2024
71df765
Update JavaScript
humitos Sep 17, 2024
003ccc9
Always include the version javascript
humitos Sep 17, 2024
5989b4c
Only include the languages if there is one
humitos Sep 17, 2024
6ced13d
Change `display_version` default
humitos Sep 17, 2024
184167c
HTML layout rework
humitos Sep 17, 2024
9008e46
Update docs
humitos Sep 17, 2024
d760b0a
HTML layout fix
humitos Sep 17, 2024
96cfa2d
Docs typo
humitos Sep 17, 2024
98c9592
Update CSS
humitos Sep 17, 2024
c0a66d9
Updates from review
humitos Sep 19, 2024
b923b6f
re-compile CSS
humitos Sep 19, 2024
2fc2aaa
Update CSS
humitos Sep 19, 2024
ece85df
Apply suggestions from code review
humitos Sep 19, 2024
26cdafa
Use the prettier to lint the file
humitos Sep 19, 2024
9afe946
Merge branch 'humitos/selectors' of github.com:readthedocs/sphinx_rtd…
humitos Sep 19, 2024
a362256
Whitespaces
humitos Sep 19, 2024
2bfc378
Update event listener
humitos Sep 19, 2024
d3ea70a
Update CSS
humitos Sep 19, 2024
474290d
Update CSS
humitos Sep 19, 2024
7b63004
Remove language switch if there are not translations
humitos Sep 19, 2024
dbd7fd3
Tune version and language selector styles (#1603)
agjohnson Sep 20, 2024
3d795d2
Debug: trigger Read the Docs Addons event to test/debug locally (#1606)
humitos Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions docs/configuring.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ For example:
'analytics_id': 'G-XXXXXXXXXX', # Provided by Google in your dashboard
'analytics_anonymize_ip': False,
'logo_only': False,
'display_version': True,
'prev_next_buttons_location': 'bottom',
'style_external_links': False,
'vcs_pageview_mode': '',
'style_nav_header_background': 'white',
'flyout_display': 'hidden',
'version_selector': True,
'language_selector': True,
# Toc options
'collapse_navigation': True,
'sticky_navigation': True,
Expand Down Expand Up @@ -139,7 +140,11 @@ Miscellaneous options
If ``True``, the version number is shown at the top of the sidebar.

:type: boolean
:default: ``True``
:default: ``False``

.. deprecated:: 3.0.0

Removed in favor of ``version_selector`` and ``language_selector``.

.. confval:: logo_only

Expand Down Expand Up @@ -192,6 +197,26 @@ Miscellaneous options
:type: str
:default: ``hidden``

.. confval:: version_selector

Display a version selector below the title.
This feature makes usage of `Read the Docs Addons <https://docs.readthedocs.io/page/addons.html>`_ for this,
so it's required the documentation to be hosted on Read the Docs.
It only appears when there are more than 1 active version.

:type: boolean
:default: ``True``

.. confval:: language_selector

Display a language selector below the title.
This feature makes usage of `Read the Docs Addons <https://docs.readthedocs.io/page/addons.html>`_ for this,
so it's required the documentation to be served on Read the Docs.
It only appears when there is more than 1 active language.

:type: boolean
:default: ``True``


File-wide metadata
==================
Expand Down
15 changes: 6 additions & 9 deletions sphinx_rtd_theme/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
{%- endfor %}
<script src="{{ pathto('_static/js/theme.js', 1) }}"></script>

{%- if READTHEDOCS and theme_flyout_display != "hidden" %}
{%- if READTHEDOCS %}
<script src="{{ pathto('_static/js/versions.js', 1) }}"></script>
{%- endif %}

Expand Down Expand Up @@ -124,14 +124,11 @@
{%- endif %}
</a>

{%- if theme_display_version %}
{%- set nav_version = version %}
{%- if READTHEDOCS and current_version %}
{%- set nav_version = current_version %}
{%- endif %}
{%- if nav_version %}
<div class="version">
{{ nav_version }}
{%- if READTHEDOCS %}
{%- if theme_version_selector or theme_language_selector %}
<div class="switch-menus">
<div class="version-switch"></div>
<div class="language-switch"></div>
</div>
{%- endif %}
{%- endif %}
Expand Down
2 changes: 1 addition & 1 deletion sphinx_rtd_theme/static/css/theme.css

Large diffs are not rendered by default.

185 changes: 141 additions & 44 deletions sphinx_rtd_theme/static/js/versions.js_t
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
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;
}
const themeFlyoutDisplay = "{{ theme_flyout_display }}";
const themeVersionSelector = "{{ theme_version_selector }}";
const themeLanguageSelector = "{{ theme_language_selector }}";

if (themeFlyoutDisplay === "attached") {
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) {
Expand All @@ -24,12 +32,15 @@ function renderLanguages(config) {
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>
${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")}
`,
)
.join("\n")}
</dl>
`;
return versionsHTML;
Expand All @@ -48,42 +59,45 @@ function renderLanguages(config) {
const downloadsHTML = `
<dl>
<dt>{{ _('Downloads') }}</dt>
${ Object.entries(config.versions.current.downloads).map(
([name, url]) => `
${Object.entries(config.versions.current.downloads)
.map(
([name, url]) => `
<dd>
<a href="${ url }">${ downloadsNameDisplay[name] }</a>
<a href="${url}">${downloadsNameDisplay[name]}</a>
</dd>
`).join("\n")}
`,
)
.join("\n")}
</dl>
`;
return downloadsHTML;
}

document.addEventListener("readthedocs-addons-data-ready", function(event) {
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 }
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) }
${renderLanguages(config)}
${renderVersions(config)}
${renderDownloads(config)}
<dl>
<dt>{{ _('On Read the Docs') }}</dt>
<dd>
<a href="${ config.projects.current.urls.home }">{{ _('Project Home') }}</a>
<a href="${config.projects.current.urls.home}">{{ _('Project Home') }}</a>
</dd>
<dd>
<a href="${ config.projects.current.urls.builds }">{{ _('Builds') }}</a>
<a href="${config.projects.current.urls.builds}">{{ _('Builds') }}</a>
</dd>
<dd>
<a href="${ config.projects.current.urls.downloads }">{{ _('Downloads') }}</a>
<a href="${config.projects.current.urls.downloads}">{{ _('Downloads') }}</a>
</dd>
</dl>
<dl>
Expand Down Expand Up @@ -112,14 +126,97 @@ function renderLanguages(config) {
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);
});
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);
});
});
document
.querySelector("[role='search'] input")
.addEventListener("focusin", () => {
const event = new CustomEvent("readthedocs-search-show");
document.dispatchEvent(event);
});
});
}

if (themeLanguageSelector || themeVersionSelector) {
function onSelectorSwitch(event) {
const option = event.target.selectedIndex;
const item = event.target.options[option];
window.location.href = item.dataset.url;
}

document.addEventListener("readthedocs-addons-data-ready", function (event) {
const config = event.detail.data();

const versionSwitch = document.querySelector(
"div.switch-menus > div.version-switch",
);
if (themeVersionSelector) {
let versions = config.versions.active;
if (config.versions.current.type === "external") {
versions.unshift(config.versions.current);
}
const versionSelect = `
<select>
${versions
.map(
(version) => `
<option
value="${version.slug}"
${config.versions.current.slug === version.slug ? 'selected="selected"' : ""}
data-url="${version.urls.documentation}">
${version.slug}
</option>`,
)
.join("\n")}
</select>
`;

versionSwitch.innerHTML = versionSelect;
versionSwitch.firstElementChild.addEventListener("change", onSelectorSwitch);
}

const languageSwitch = document.querySelector(
"div.switch-menus > div.language-switch",
);

if (themeLanguageSelector) {
if (config.projects.translations.length) {
// Add the current language to the options on the selector
let languages = config.projects.translations.concat(
config.projects.current,
);
languages = languages.sort((a, b) =>
a.language.name.localeCompare(b.language.name),
);

const languageSelect = `
<select>
${languages
.map(
(language) => `
<option
value="${language.language.code}"
${config.projects.current.slug === language.slug ? 'selected="selected"' : ""}
data-url="${language.urls.documentation}">
${language.language.name}
</option>`,
)
.join("\n")}
</select>
`;

languageSwitch.innerHTML = languageSelect;
languageSwitch.firstElementChild.addEventListener("change", onSelectorSwitch);
}
else {
languageSwitch.remove();
}
}
});
}
3 changes: 2 additions & 1 deletion sphinx_rtd_theme/theme.conf
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ navigation_depth = 4
includehidden = True
titles_only =
logo_only =
display_version = True
prev_next_buttons_location = bottom
style_external_links = False
style_nav_header_background =
vcs_pageview_mode =
flyout_display = hidden
version_selector = True
language_selector = True
48 changes: 45 additions & 3 deletions src/sass/_theme_layout.sass
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ html
padding: ($base-line-height / 6) ($base-line-height / 4)
margin-bottom: $gutter / 2
max-width: 100%
&:hover
&:hover, &active, &focus
background: rgba(255, 255, 255, 0.1)
img.logo
display: block // display on its own line all the time
Expand All @@ -228,13 +228,55 @@ html
max-width: 100% // shrink on mobile, if appropriate
background: rgba(0, 0, 0, 0) // make hover background of parent show up properly
&.icon
display: block
img.logo
margin-top: 0.85em // space it away from the title text
> div.version
> div.switch-menus
position: relative
display: block
margin-top: -1 * $gutter / 4
margin-bottom: $gutter / 2
font-weight: normal
color: rgba(255, 255, 255, 0.3)
color: rgba(255, 255,255, 0.3)
> div.version-switch, > div.language-switch
display: inline-block
padding: .2em
select
// Provide room for dropdown icon
display: inline-block
margin-right: -2rem
padding-right: 2rem
max-width: $nav-desktop-width * .8
// Alter base select styles
text-align-last: center
background: none
border: none
border-radius: 0em
box-shadow: none
font-family: $base-font-family
font-size: 1em
font-weight: normal
color: rgba(255, 255, 255, .3)
cursor: pointer
// Allow for padding
appearance: none
-webkit-appearance: none
-moz-appearance: none
&:hover, &:active, &:focus
background: rgba(255, 255, 255, .1)
color: rgba(255, 255, 255, .5)
&:has(> select):after
display: inline-block
width: 1.5em
height: 100%
padding: .1em
content: "\f0d7"
font-size: 1em
line-height: 1.2em
font-family: FontAwesome
text-align: center
pointer-events: none
box-sizing: border-box

.wy-nav .wy-menu-vertical
header
Expand Down