diff --git a/python_docs_theme/layout.html b/python_docs_theme/layout.html index a9a0e6f..bf4e425 100644 --- a/python_docs_theme/layout.html +++ b/python_docs_theme/layout.html @@ -37,6 +37,7 @@ <h3>{{ _('Navigation') }}</h3> {{ reldelim2 }} </li> {%- endif %} + <li class="right">{{ themeselector() }}{{ reldelim2 }}</li> {% endblock %} </ul> </div> @@ -47,25 +48,35 @@ <h3>{{ _('Navigation') }}</h3> {%- if builder != "htmlhelp" %} <div class="inline-search" role="search"> <form class="inline-search" action="{{ pathto('search') }}" method="get"> - <input placeholder="{{ _('Quick search') }}" aria-label="{{ _('Quick search') }}" type="text" name="q" /> + <input placeholder="{{ _('Quick search') }}" aria-label="{{ _('Quick search') }}" type="search" name="q" /> <input type="submit" value="{{ _('Go') }}" /> - <input type="hidden" name="check_keywords" value="yes" /> - <input type="hidden" name="area" value="default" /> </form> </div> {%- endif %} {%- endmacro %} +{%- macro themeselector() %} +<label class="theme-selector-label"> + {{ _('Theme') }} + <select class="theme-selector" oninput="activateTheme(this.value)"> + <option value="auto" selected>{{ _('Auto') }}</option> + <option value="light">{{ _('Light') }}</option> + <option value="dark">{{ _('Dark') }}</option> + </select> +</label> +{%- endmacro %} + {% block relbar1 %} {% if builder != 'qthelp' %} {{ relbar() }} {% endif %} {% endblock %} {% block relbar2 %} {% if builder != 'qthelp' %} {{ relbar() }} {% endif %} {% endblock %} - {%- block extrahead -%} + <link rel="stylesheet" href="{{ pathto('_static/pydoctheme_dark.css', 1) }}" media="(prefers-color-scheme: dark)" id="pydoctheme_dark_css"> <link rel="shortcut icon" type="image/png" href="{{ pathto('_static/' + theme_root_icon, 1) }}" /> {%- if builder != "htmlhelp" %} {%- if not embedded %} <script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script> <script type="text/javascript" src="{{ pathto('_static/menu.js', 1) }}"></script> + <script type="text/javascript" src="{{ pathto('_static/themetoggle.js', 1) }}"></script> {%- endif -%} {%- endif -%} {{ super() }} @@ -82,28 +93,30 @@ <h3>{{ _('Navigation') }}</h3> <div class="mobile-nav"> <input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation" aria-pressed="false" aria-expanded="false" role="button" aria-label="{{ _('Menu')}}" /> - <label for="menuToggler" class="toggler__label"> - <span></span> - </label> <nav class="nav-content" role="navigation"> - <a href="{{ theme_root_url }}" class="nav-logo"> - <img src="{{ pathto('_static/py.svg', 1) }}" alt="Logo"/> - </a> - <div class="version_switcher_placeholder"></div> - {%- if pagename != "search" and builder != "singlehtml" %} - <form role="search" class="search" action="{{ pathto('search') }}" method="get"> - <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon"> - <path fill-rule="nonzero" - d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" fill="#444"></path> - </svg> - <input type="text" name="q" aria-label="{{ _('Quick search') }}"/> - <input type="submit" value="{{ _('Go') }}"/> - </form> - {%- endif %} + <label for="menuToggler" class="toggler__label"> + <span></span> + </label> + <span class="nav-items-wrapper"> + <a href="{{ theme_root_url }}" class="nav-logo"> + <img src="{{ pathto('_static/py.svg', 1) }}" alt="Logo"/> + </a> + <span class="version_switcher_placeholder"></span> + {%- if pagename != "search" and builder != "singlehtml" %} + <form id="searchbox" role="search" class="search" action="{{ pathto('search') }}" method="get"> + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon"> + <path fill-rule="nonzero" fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path> + </svg> + <input placeholder="{{ _('Quick search') }}" aria-label="{{ _('Quick search') }}" type="search" name="q" /> + <input type="submit" value="{{ _('Go') }}"/> + </form> + {%- endif %} + </span> </nav> <div class="menu-wrapper"> <nav class="menu" role="navigation" aria-label="main navigation"> <div class="language_switcher_placeholder"></div> + {{ themeselector() }} {%- if logo %} <p class="logo"> <a href="{{ pathto('index') }}"> diff --git a/python_docs_theme/static/caret-down.svg b/python_docs_theme/static/caret-down.svg deleted file mode 100644 index fc55b34..0000000 --- a/python_docs_theme/static/caret-down.svg +++ /dev/null @@ -1 +0,0 @@ -<svg viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg"><path d="M7.45896 11.25H22.5351c1.043 0 1.5645 1.2598.8262 1.998l-7.5352 7.5411c-.457.457-1.2011.457-1.6582 0L6.63279 13.248c-.73828-.7382-.2168-1.998.82617-1.998z" fill="#444"/></svg> diff --git a/python_docs_theme/static/pydoctheme.css b/python_docs_theme/static/pydoctheme.css index 3530bf9..6c141f8 100644 --- a/python_docs_theme/static/pydoctheme.css +++ b/python_docs_theme/static/pydoctheme.css @@ -1,7 +1,35 @@ -@import url("default.css"); +@import url('classic.css'); + +/* unset some styles from the classic stylesheet */ +div.document, +div.body, +div.related, +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6, +div.sphinxsidebar a, +div.sphinxsidebar p, +div.sphinxsidebar ul, +div.sphinxsidebar h3, +div.sphinxsidebar h3 a, +div.sphinxsidebar h4, +.menu a, +.menu p, +.menu ul, +.menu h3, +.menu h3 a, +.menu h4, +table.docutils td, +table.indextable tr.cap, +pre { + background-color: inherit; + color: inherit; +} body { - background-color: white; margin-left: 1em; margin-right: 1em; } @@ -12,19 +40,23 @@ body { } div.related { + margin-top: 0.5em; margin-bottom: 1.2em; padding: 0.5em 0; - border-bottom: 1px solid #ccc; - margin-top: 0.5em; + border-width: 1px; + border-color: #ccc; } -div.related a:hover { - color: #0095C4; +.mobile-nav + div.related { + border-bottom-style: solid; +} + +.document + div.related { + border-top-style: solid; } -div.related ~ div.related { - border-top: 1px solid #ccc; - border-bottom: none; +div.related a:hover { + color: #0095c4; } .related .switchers { @@ -35,19 +67,18 @@ div.related ~ div.related { margin-right: 5px; } -.version_switcher_placeholder, -.language_switcher_placeholder { - padding-left: 5px; - background-color: white; +div.related ul::after { + content: ''; + clear: both; + display: block; } -.inline-search { - display: inline; -} +.inline-search, form.inline-search input { display: inline; } -form.inline-search input[type="submit"] { + +form.inline-search input[type='submit'] { width: 40px; } @@ -60,13 +91,15 @@ div.sphinxsidebar { position: sticky; top: 0; max-height: 100vh; - background-color: #eeeeee; + color: #444; + background-color: #eee; border-radius: 5px; line-height: 130%; font-size: smaller; } -div.sphinxsidebar h3, div.sphinxsidebar h4 { +div.sphinxsidebar h3, +div.sphinxsidebar h4 { margin-top: 1.5em; } @@ -86,18 +119,19 @@ div.sphinxsidebarwrapper > ul > li > ul > li { } div.sphinxsidebar a:hover { - color: #0095C4; + color: #0095c4; } form.inline-search input, -div.sphinxsidebar input { - font-family: 'Lucida Grande',Arial,sans-serif; +div.sphinxsidebar input, +div.related input { + font-family: 'Lucida Grande', Arial, sans-serif; border: 1px solid #999999; font-size: smaller; border-radius: 3px; } -div.sphinxsidebar input[type=text] { +div.sphinxsidebar input[type='text'] { max-width: 150px; } @@ -126,7 +160,8 @@ div.body pre { border: 1px solid #ac9; } -div.body div.admonition, div.body div.impl-detail { +div.body div.admonition, +div.body div.impl-detail { border-radius: 3px; } @@ -147,7 +182,7 @@ div.body a:visited { } div.body a:hover { - color: #00B0E4; + color: #00b0e4; } tt, code, pre { @@ -155,15 +190,20 @@ tt, code, pre { font-size: 96.5%; } -div.body tt, div.body code { +div.body tt, +div.body code { border-radius: 3px; } -div.body tt.descname, div.body code.descname { +div.body tt.descname, +div.body code.descname { font-size: 120%; } -div.body tt.xref, div.body a tt, div.body code.xref, div.body a code { +div.body tt.xref, +div.body a tt, +div.body code.xref, +div.body a code { font-weight: normal; } @@ -175,26 +215,24 @@ table.docutils { margin-bottom: 10px; } -table.docutils td, table.docutils th { +table.docutils td, +table.docutils th { border: 1px solid #ddd !important; border-radius: 3px; + padding: 0.3em 0.5em; } -table p, table li { +table p, +table li { text-align: left !important; } table.docutils th { background-color: #eee; - padding: 0.3em 0.5em; } -table.docutils td { - background-color: white; - padding: 0.3em 0.5em; -} - -table.footnote, table.footnote td { +table.footnote, +table.footnote td { border: 0 !important; } @@ -206,7 +244,7 @@ div.footer { } div.footer a:hover { - color: #0095C4; + color: #0095c4; } .refcount { @@ -217,10 +255,6 @@ div.footer a:hover { color: #229; } -.highlight { - background: none !important; -} - dl > dt span ~ em { font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", "Liberation Mono", Menlo, Monaco, Consolas, monospace; } @@ -229,6 +263,10 @@ dl > dt span ~ em { padding-left: 20px; } +.theme-selector { + margin-left: .5em; +} + div.genindex-jumpbox, div.genindex-jumpbox > p { display: inline-flex; @@ -289,7 +327,6 @@ div.genindex-jumpbox a { position: fixed; top: 0; left: 0; - background-color: white; box-shadow: rgba(0, 0, 0, 0.25) 0 0 2px 0; z-index: 1; } @@ -298,111 +335,79 @@ div.genindex-jumpbox a { } .nav-content { position: absolute; - z-index: 2; - left: 0; - top: 0; + z-index: 1; height: 40px; width: 100%; - max-width: 100vw; - padding: 0 1rem 0 45px; display: flex; - align-items: center; background-color: white; } - .nav-logo { - margin-right: 0.7rem; + .nav-items-wrapper { display: flex; - flex: 0 0 auto; + flex: auto; + padding: .25rem; + align-items: stretch; + } + .nav-logo { + margin-right: 1rem; + flex-shrink: 0; + align-self: center; } .nav-content img { + display: block; width: 20px; - height: auto; } .version_switcher_placeholder { - flex: 0 1 0; margin-right: 1rem; } + .version_switcher_placeholder > select { + height: 100%; + } .nav-content .search { display: flex; - flex: 1 1 auto; - align-items: center; - padding: 0 0 0 2px; + flex: auto; border: 1px solid #a9a9a9; - height: 30px; - overflow: hidden; - } - .nav-content .search:hover { - box-shadow: 0 1px 6px 0 rgba(32,33,36,0.28); - border-color: rgba(223,225,229,0); + align-items: stretch; } - .nav-content .search input[type=text] { + .nav-content .search input[type=search] { border: 0; - outline: 0; - box-shadow: none; - width: 40px; - height: 28px; - flex: 1 1 auto; + padding-left: 24px; + width: 100%; + flex: 1; } .nav-content .search input[type=submit] { height: 100%; - appearance: none; - -webkit-appearance: none; - border: 1px solid transparent; - border-left-color: #a9a9a9; box-shadow: none; + border: 0; + border-left: 1px solid #a9a9a9; cursor: pointer; - background-color: #f0f0f0; margin-right: 0; } - .nav-content .search input[type=submit]:hover { - border-color: #a9a9a9; - } .nav-content .search svg { - flex: 0 0 20px; - fill: #333; + position: absolute; + align-self: center; + padding-left: 4px; } .toggler__input { - width: 40px; - height: 40px; - left: 0; - opacity: 0; - position: absolute; - z-index: 3; - margin: 0; + display: none; } .toggler__label { width: 40px; - height: 40px; - margin: 0; - position: absolute; cursor: pointer; - top: 0; - left: 0; - background-color: transparent; - border: 1px solid white; - box-shadow: none; - z-index: 3; display: flex; align-items: center; justify-content: center; - padding: 0 8px; - } - .toggler__label:focus { - background-color: #eee; - border: 1px solid #ededed; - box-shadow: rgba(0, 0, 0, 0.25) 1px 0 2px 0; + padding: 8px; + flex-shrink: 0; } - .toggler__label:hover { - background-color: #eee; - border: 1px solid #ededed; - box-shadow: rgba(0, 0, 0, 0.25) 1px 0 2px 0; + .toggler__label:hover, .toggler__label:focus { + background-color: rgba(127 127 127 / 50%); } .toggler__label > span { position: relative; flex: none; height: 2px; width: 100%; - background: #444; + background: currentColor; transition: all 400ms ease; } .toggler__label > span::before, @@ -418,17 +423,17 @@ div.genindex-jumpbox a { .toggler__label > span::after { top: 8px; } - .toggler__input:checked ~ .toggler__label span { + .toggler__input:checked ~ nav > .toggler__label span { transform: rotate(135deg); } - .toggler__input:checked ~ .toggler__label span::before { + .toggler__input:checked ~ nav > .toggler__label span::before { transform: rotate(90deg); } - .toggler__input:checked ~ .toggler__label span::before, - .toggler__input:checked ~ .toggler__label span::after { + .toggler__input:checked ~ nav > .toggler__label span::before, + .toggler__input:checked ~ nav > .toggler__label span::after { top: 0; } - .toggler__input:checked:hover ~ .toggler__label span { + .toggler__input:checked:hover ~ nav > .toggler__label span { transform: rotate(315deg); } .toggler__input:checked ~ .menu-wrapper { @@ -446,6 +451,7 @@ div.genindex-jumpbox a { width: 300px; height: 100%; background-color: #eee; + color: #444444; box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); overflow-y: auto; } @@ -465,7 +471,6 @@ div.genindex-jumpbox a { font-size: 1.3em; } .menu-wrapper h3 { - color: #444444; font-size: 1.4em; } .menu-wrapper h3 + p, @@ -474,7 +479,6 @@ div.genindex-jumpbox a { } .menu a { font-size: smaller; - color: #444444; text-decoration: none; } .menu ul { @@ -490,38 +494,9 @@ div.genindex-jumpbox a { .menu ul li { margin-bottom: 0.5rem; } - .language_switcher_placeholder, - .version_switcher_placeholder { - position: relative; - border: 1px solid #a8a8a8; - height: 30px; - padding-right: 7px; - } .language_switcher_placeholder { margin-top: 2rem; } - .language_switcher_placeholder::after, - .version_switcher_placeholder::after { - content: url('../_static/caret-down.svg'); - position: absolute; - top: 7px; - width: 15px; - height: 15px; - right: 0; - pointer-events: none; - } - .language_switcher_placeholder select, - .version_switcher_placeholder select { - -webkit-appearance: none; - appearance: none; - border: 0; - height: 100%; - background-color: white; - } - .language_switcher_placeholder:focus-visible, - .version_switcher_placeholder:focus-visible { - outline-offset: 5px; - } .language_switcher_placeholder select { width: 100%; } @@ -534,6 +509,16 @@ div.genindex-jumpbox a { width: 100%; overflow-x: auto; } + + .menu .theme-selector-label { + margin-top: .5em; + display: flex; + width: 100%; + } + + .menu .theme-selector { + flex: auto; + } } @media (min-width: 1024px) { diff --git a/python_docs_theme/static/pydoctheme_dark.css b/python_docs_theme/static/pydoctheme_dark.css new file mode 100644 index 0000000..4aa657b --- /dev/null +++ b/python_docs_theme/static/pydoctheme_dark.css @@ -0,0 +1,122 @@ + +/* Browser elements */ +:root { + scrollbar-color: #616161 transparent; + color-scheme: dark; +} + +html, +body { + background-color: #222; + color: rgba(255, 255, 255, 0.87); +} + +div.related { + color: rgba(255, 255, 255, 0.7); /* classic overwrite */ + border-color: #424242; +} + +/* SIDEBAR */ +div.sphinxsidebar, .menu-wrapper { + background-color: #333; + color: inherit; +} + +#sidebarbutton { + /* important to overwrite style attribute */ + background-color: #555 !important; + color: inherit !important; +} + +div.sidebar, aside.sidebar { + background-color: #424242; + border-color: #616161; +} + +/* ANCHORS AND HIGHLIGHTS */ +div.body a { + color: #7af; +} + +div.body a:visited { + color: #09e; +} + +a.headerlink:hover { + background-color: #424242; +} + +div.related a { + color: currentColor; +} + +div.footer, +div.footer a { + color: currentColor; /* classic overwrites */ +} + +dt:target, +span.highlighted { + background-color: #616161; +} + +/* Below for most things in text */ + +dl.field-list > dt { + background-color: #434; +} + +table.docutils td, +table.docutils th { + border-color: #616161 !important; +} + +table.docutils th { + background-color: #424242; +} + +.refcount { + color: #afa; +} + +.stableabi { + color: #bbf; +} + +div.body pre { + border-color: #616161; +} + +code { + background-color: #424242; +} + +div.body div.seealso { + background-color: rgba(255, 255, 0, 0.1); +} + +div.warning { + background-color: rgba(255, 0, 0, 0.2); +} + +.warning code { + background-color: rgba(255, 0, 0, 0.5); +} + +div.topic, +div.note { + background-color: rgba(255, 255, 255, 0.1); + border-color: currentColor; +} + +.note code { + background-color: rgba(255, 255, 255, 0.1); +} + +.mobile-nav { + box-shadow: rgba(255, 255, 255, 0.25) 0 0 2px 0; +} + +.nav-content { + background-color: black; +} diff --git a/python_docs_theme/static/themetoggle.js b/python_docs_theme/static/themetoggle.js new file mode 100644 index 0000000..f9394c6 --- /dev/null +++ b/python_docs_theme/static/themetoggle.js @@ -0,0 +1,24 @@ +const pydocthemeDark = document.getElementById('pydoctheme_dark_css') +const pygmentsDark = document.getElementById('pygments_dark_css') +const themeSelectors = document.getElementsByClassName('theme-selector') + +function activateTheme(theme) { + localStorage.setItem('currentTheme', theme); + [...themeSelectors].forEach(e => e.value = theme) + switch (theme) { + case 'light': + pydocthemeDark.media = 'not all' + pygmentsDark.media = 'not all' + break; + case 'dark': + pydocthemeDark.media = 'all' + pygmentsDark.media = 'all' + break; + default: + // auto + pydocthemeDark.media = '(prefers-color-scheme: dark)' + pygmentsDark.media = '(prefers-color-scheme: dark)' + } +} + +activateTheme(localStorage.getItem('currentTheme') || 'auto') diff --git a/python_docs_theme/theme.conf b/python_docs_theme/theme.conf index 11670d3..a011f5b 100644 --- a/python_docs_theme/theme.conf +++ b/python_docs_theme/theme.conf @@ -2,6 +2,7 @@ inherit = default stylesheet = pydoctheme.css?2022.1 pygments_style = default +pygments_dark_style = monokai [options] bodyfont = 'Lucida Grande', Arial, sans-serif