diff --git a/python_docs_theme/__init__.py b/python_docs_theme/__init__.py
index f0ddc06..ca5a424 100644
--- a/python_docs_theme/__init__.py
+++ b/python_docs_theme/__init__.py
@@ -2,6 +2,7 @@
from pathlib import Path
+from markupsafe import Markup, escape
from sphinx.locale import get_translation
TYPE_CHECKING = False
@@ -18,6 +19,12 @@
MESSAGE_CATALOG_NAME = "python-docs-theme"
+def _tobool(val: object) -> bool:
+ if isinstance(val, str):
+ return val.lower() in {"true", "1", "yes", "on"}
+ return bool(val)
+
+
def add_translation_to_context(
app: Sphinx,
pagename: str,
@@ -37,12 +44,37 @@ def combined(message: str) -> str:
context["_"] = context["gettext"] = context["ngettext"] = combined
+def add_html_dir_to_context(
+ app: Sphinx,
+ pagename: str,
+ templatename: str,
+ context: dict[str, Any],
+ doctree: None,
+) -> None:
+ language = app.config.language or "en"
+
+ is_rtl_option = context.get("theme_is_rtl", "")
+ if is_rtl_option in (None, ""):
+ is_rtl = False
+ else:
+ is_rtl = _tobool(is_rtl_option)
+
+ dir_attr = "rtl" if is_rtl else "ltr"
+
+ content_root = context.get("content_root", "")
+ lang_part = f' lang="{escape(language)}"' if language is not None else ""
+ context["html_tag"] = Markup(
+ f''
+ )
+
+
def setup(app: Sphinx) -> ExtensionMetadata:
app.require_sphinx("7.3")
app.add_html_theme("python_docs_theme", str(THEME_PATH))
app.add_message_catalog(MESSAGE_CATALOG_NAME, LOCALE_DIR)
app.connect("html-page-context", add_translation_to_context)
+ app.connect("html-page-context", add_html_dir_to_context)
return {
"version": __version__,
diff --git a/python_docs_theme/layout.html b/python_docs_theme/layout.html
index 1903fad..cbdee99 100644
--- a/python_docs_theme/layout.html
+++ b/python_docs_theme/layout.html
@@ -6,7 +6,7 @@
{{ _('Navigation') }}
{%- for rellink in rellinks %}
- -
+
-
{{ rellink[3] }}
diff --git a/python_docs_theme/static/pydoctheme.css b/python_docs_theme/static/pydoctheme.css
index aa9622d..1f527bd 100644
--- a/python_docs_theme/static/pydoctheme.css
+++ b/python_docs_theme/static/pydoctheme.css
@@ -108,7 +108,7 @@ div.related a:hover {
}
.switchers > div {
- margin-right: 5px;
+ margin-inline-end: 5px;
}
div.related ul::after {
@@ -117,6 +117,17 @@ div.related ul::after {
display: block;
}
+div.related ul {
+ padding: 0;
+ padding-inline-start: 10px;
+}
+
+html[dir='rtl'] div.related ul li.right {
+ float: left;
+ margin-right: 0;
+ margin-left: 5px;
+}
+
.inline-search,
form.inline-search input {
display: inline;
@@ -130,6 +141,7 @@ form.inline-search input[type='submit'] {
div.document {
display: flex;
+ flex-direction: row;
/* Don't let long code literals extend beyond the right side of the screen */
overflow-wrap: break-word;
}
@@ -142,6 +154,9 @@ span.pre {
div.sphinxsidebar {
display: flex;
width: min(25vw, 350px);
+ flex-shrink: 0;
+ margin: 0;
+ order: 0;
float: none;
position: sticky;
top: 0;
@@ -158,8 +173,14 @@ div.sphinxsidebar h4 {
margin-top: 1.5em;
}
-div.bodywrapper {
- margin-left: min(25vw, 350px);
+div.document div.bodywrapper {
+ margin: 0;
+}
+
+div.documentwrapper {
+ flex: 1;
+ min-width: 0;
+ order: 1;
}
div.sphinxsidebarwrapper {
@@ -179,6 +200,11 @@ div.sphinxsidebarwrapper > ul > li > ul > li {
margin-bottom: 0.4em;
}
+div.sphinxsidebar ul ul {
+ margin-left: 0;
+ margin-inline-start: 20px;
+}
+
div.sphinxsidebar a:hover {
color: #0095c4;
}
@@ -202,7 +228,8 @@ div.sphinxsidebar input[type='text'] {
align-items: center;
width: 12px;
min-width: 12px;
- border-radius: 0 5px 5px 0;
+ border-start-end-radius: 5px;
+ border-end-end-radius: 5px;
border-left: none;
}
@@ -211,11 +238,15 @@ div.sphinxsidebar input[type='text'] {
}
div.body {
- padding: 0 0 0 1.2em;
+ padding-inline-start: 1.2em;
+}
+
+html[dir='rtl'] div.body {
+ direction: rtl;
}
div.body p, div.body dd, div.body li, div.body blockquote {
- text-align: left;
+ text-align: start;
line-height: 1.6;
}
div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 {
@@ -225,6 +256,10 @@ div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 {
}
div.body dl.field-list > dt {
line-height: 1.6;
+ padding-left: 0;
+ padding-right: 0;
+ padding-inline-start: 0.5em;
+ padding-inline-end: 5px;
}
div.body hr {
@@ -233,6 +268,16 @@ div.body hr {
height: 1px;
}
+pre,
+code,
+div.highlight,
+dl > dt span ~ em,
+.sig,
+.sig-param {
+ direction: ltr;
+ unicode-bidi: isolate;
+}
+
div.body pre {
border-radius: 3px;
border: 1px solid #ac9;
@@ -258,12 +303,10 @@ div.code-block-caption {
padding: 0.3em 0.6em;
font-size: 90%;
color: #333;
-
& + div pre {
border-top-left-radius: 0 !important;
border-top-right-radius: 0 !important;
}
-
& + div .copybutton {
border-top-right-radius: 0 !important;
}
@@ -402,7 +445,7 @@ table.docutils th {
table p,
table li {
- text-align: left !important;
+ text-align: start !important;
}
table.docutils th {
@@ -416,9 +459,9 @@ table.footnote td {
div.footer {
line-height: 150%;
- text-align: right;
+ text-align: end; /* was: text-align: right */
width: auto;
- margin-right: 10px;
+ margin-inline-end: 10px; /* was: margin-right */
}
div.footer a {
@@ -477,17 +520,12 @@ div.footer a:hover {
}
-dl > dt span ~ em,
-.sig {
- font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
-}
-
.toctree-wrapper ul {
- padding-left: 20px;
+ padding-inline-start: 20px;
}
.theme-selector {
- margin-left: .5em;
+ margin-inline-start: .5em;
}
div.genindex-jumpbox,
@@ -506,17 +544,17 @@ div.genindex-jumpbox a {
cursor: pointer;
position: absolute;
top: 0;
- right: 0;
+ right: 0; /* physical right; always, even in RTL, since code is LTR */
font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
font-size: 80%;
padding-left: .5em;
padding-right: .5em;
height: 100%;
max-height: min(100%, 2.4em);
- border-radius: 0 3px 0 0;
+ border-radius: 0 3px 0 0; /* physical — top-right corner, always */
color: #000;
background-color: #fff;
- border: 1px solid #ac9; /* follows div.body pre */
+ border: 1px solid #ac9;
display: none;
}
@@ -583,7 +621,7 @@ div.genindex-jumpbox a {
width: 100%;
position: fixed;
top: 0;
- left: 0;
+ inset-inline-start: 0;
box-shadow: rgba(0, 0, 0, 0.25) 0 0 2px 0;
z-index: 1;
}
@@ -605,7 +643,7 @@ div.genindex-jumpbox a {
align-items: stretch;
}
.nav-logo {
- margin-right: 1rem;
+ margin-inline-end: 1rem;
flex-shrink: 0;
align-self: center;
}
@@ -614,7 +652,7 @@ div.genindex-jumpbox a {
width: 20px;
}
.version_switcher_placeholder {
- margin-right: 1rem;
+ margin-inline-end: 1rem;
}
.version_switcher_placeholder > select {
height: 100%;
@@ -627,7 +665,7 @@ div.genindex-jumpbox a {
}
.nav-content .search input[type=search] {
border: 0;
- padding-left: 24px;
+ padding-inline-start: 24px;
width: 100%;
flex: 1;
}
@@ -635,14 +673,14 @@ div.genindex-jumpbox a {
height: 100%;
box-shadow: none;
border: 0;
- border-left: 1px solid #a9a9a9;
+ border-inline-start: 1px solid #a9a9a9;
cursor: pointer;
- margin-right: 0;
+ margin-inline-end: 0;
}
.nav-content .search svg {
position: absolute;
align-self: center;
- padding-left: 4px;
+ inset-inline-start: 4px;
}
.toggler__input {
display: none;
@@ -674,7 +712,7 @@ div.genindex-jumpbox a {
width: 100%;
background: inherit;
position: absolute;
- left: 0;
+ inset-inline-start: 0;
top: -8px;
}
.toggler__label > span::after {
@@ -695,7 +733,7 @@ div.genindex-jumpbox a {
}
.toggler__input:checked ~ .menu-wrapper {
visibility: visible;
- left: 0;
+ transform: translateX(0);
}
/* Sliding side menu */
@@ -703,8 +741,9 @@ div.genindex-jumpbox a {
display: block;
position: fixed;
top: 0;
- transition: left 400ms ease;
- left: -310px;
+ inset-inline-start: 0;
+ transition: transform 400ms ease;
+ transform: translateX(-100%);
width: 300px;
height: 100%;
background-color: #eee;
@@ -712,12 +751,18 @@ div.genindex-jumpbox a {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
overflow-y: auto;
}
+ html[dir='rtl'] .menu-wrapper {
+ transform: translateX(100%);
+ }
.menu-wrapper.open {
visibility: visible;
- left: 0;
+ transform: translateX(0);
}
.menu {
- padding: 40px 10px 30px 20px;
+ padding-block-start: 40px;
+ padding-inline-end: 10px;
+ padding-block-end: 30px;
+ padding-inline-start: 20px;
}
.menu-wrapper h3,
.menu-wrapper h4 {
@@ -742,10 +787,10 @@ div.genindex-jumpbox a {
list-style: none;
line-height: 1.4;
overflow-wrap: break-word;
- padding-left: 0;
+ padding-inline-start: 0;
}
.menu ul ul {
- margin-left: 20px;
+ margin-inline-start: 20px;
list-style: square;
}
.menu ul li {
@@ -801,26 +846,26 @@ div.versionadded,
div.versionchanged,
div.deprecated,
div.deprecated-removed {
- border-left: 3px solid;
+ border-inline-start: 3px solid;
padding: 0 1rem;
}
div.versionadded {
- border-left-color: var(--versionadded-border);
+ border-inline-start-color: var(--versionadded-border);
}
div.versionchanged {
- border-left-color: var(--versionchanged-border);
+ border-inline-start-color: var(--versionchanged-border);
}
div.deprecated,
div.deprecated-removed,
div.versionremoved {
- border-left-color: var(--deprecated-border);
+ border-inline-start-color: var(--deprecated-border);
}
div.soft-deprecated {
- border-left-color: var(--soft-deprecated-border);
+ border-inline-start-color: var(--soft-deprecated-border);
}
div.versionadded .versionmodified {
diff --git a/python_docs_theme/theme.toml b/python_docs_theme/theme.toml
index 1d3cdbd..c0f9c79 100644
--- a/python_docs_theme/theme.toml
+++ b/python_docs_theme/theme.toml
@@ -27,6 +27,7 @@ headbgcolor = "white"
headlinkcolor = "#aaaaaa"
codebgcolor = "#eeffcc"
codetextcolor = "#333333"
+is_rtl = "false"
hosted_on = ""
issues_url = ""