diff --git a/docs/_static/codeblocks.css b/docs/_static/codeblocks.css new file mode 100644 index 00000000..f64d725f --- /dev/null +++ b/docs/_static/codeblocks.css @@ -0,0 +1,142 @@ +/* light theme: default */ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f0f0f0; } +.highlight .c { color: #60a0b0; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #40a070 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #40a070 } /* Literal.Number.Bin */ +.highlight .mf { color: #40a070 } /* Literal.Number.Float */ +.highlight .mh { color: #40a070 } /* Literal.Number.Hex */ +.highlight .mi { color: #40a070 } /* Literal.Number.Integer */ +.highlight .mo { color: #40a070 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ + +/* dark theme: modified "native" */ +:root[data-theme="dark"] .highlight pre { background-color: #2a2a2e } +:root[data-theme="dark"] .highlight .hll { background-color: #2a2a2e } +:root[data-theme="dark"] .highlight .c { color: #999999; font-style: italic } /* Comment */ +:root[data-theme="dark"] .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +:root[data-theme="dark"] .highlight .g { color: #d0d0d0 } /* Generic */ +:root[data-theme="dark"] .highlight .k { color: #6ab825; font-weight: bold } /* Keyword */ +:root[data-theme="dark"] .highlight .l { color: #d0d0d0 } /* Literal */ +:root[data-theme="dark"] .highlight .n { color: #d0d0d0 } /* Name */ +:root[data-theme="dark"] .highlight .o { color: #d0d0d0 } /* Operator */ +:root[data-theme="dark"] .highlight .x { color: #d0d0d0 } /* Other */ +:root[data-theme="dark"] .highlight .p { color: #d0d0d0 } /* Punctuation */ +:root[data-theme="dark"] .highlight .cm { color: #999999; font-style: italic } /* Comment.Multiline */ +:root[data-theme="dark"] .highlight .cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */ +:root[data-theme="dark"] .highlight .c1 { color: #999999; font-style: italic } /* Comment.Single */ +:root[data-theme="dark"] .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +:root[data-theme="dark"] .highlight .gd { color: #d22323 } /* Generic.Deleted */ +:root[data-theme="dark"] .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +:root[data-theme="dark"] .highlight .gr { color: #d22323 } /* Generic.Error */ +:root[data-theme="dark"] .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +:root[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */ +:root[data-theme="dark"] .highlight .go { color: #cccccc } /* Generic.Output */ +:root[data-theme="dark"] .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +:root[data-theme="dark"] .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +:root[data-theme="dark"] .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +:root[data-theme="dark"] .highlight .gt { color: #d22323 } /* Generic.Traceback */ +:root[data-theme="dark"] .highlight .kc { color: #6ab825; font-weight: bold } /* Keyword.Constant */ +:root[data-theme="dark"] .highlight .kd { color: #6ab825; font-weight: bold } /* Keyword.Declaration */ +:root[data-theme="dark"] .highlight .kn { color: #6ab825; font-weight: bold } /* Keyword.Namespace */ +:root[data-theme="dark"] .highlight .kp { color: #6ab825 } /* Keyword.Pseudo */ +:root[data-theme="dark"] .highlight .kr { color: #6ab825; font-weight: bold } /* Keyword.Reserved */ +:root[data-theme="dark"] .highlight .kt { color: #6ab825; font-weight: bold } /* Keyword.Type */ +:root[data-theme="dark"] .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +:root[data-theme="dark"] .highlight .m { color: #7fb1d7 } /* Literal.Number */ +:root[data-theme="dark"] .highlight .s { color: #ed9d13 } /* Literal.String */ +:root[data-theme="dark"] .highlight .na { color: #bbbbbb; } /* Name.Attribute */ +:root[data-theme="dark"] .highlight .nb { color: #29a5b3; } /* Name.Builtin */ +:root[data-theme="dark"] .highlight .nc { color: #6494d8;} /* Name.Class */ +:root[data-theme="dark"] .highlight .no { color: #40ffff; } /* Name.Constant */ +:root[data-theme="dark"] .highlight .nd { color: #ffa500; } /* Name.Decorator */ +:root[data-theme="dark"] .highlight .ni { color: #d0d0d0; } /* Name.Entity */ +:root[data-theme="dark"] .highlight .ne { color: #bbbbbb; } /* Name.Exception */ +:root[data-theme="dark"] .highlight .nf { color: #6494d8; } /* Name.Function */ +:root[data-theme="dark"] .highlight .nl { color: #d0d0d0; } /* Name.Label */ +:root[data-theme="dark"] .highlight .nn { color: #6494d8;} /* Name.Namespace */ +:root[data-theme="dark"] .highlight .nx { color: #d0d0d0; } /* Name.Other */ +:root[data-theme="dark"] .highlight .py { color: #d0d0d0; } /* Name.Property */ +:root[data-theme="dark"] .highlight .nt { color: #6ab825; font-weight: bold } /* Name.Tag */ +:root[data-theme="dark"] .highlight .nv { color: #40ffff; } /* Name.Variable */ +:root[data-theme="dark"] .highlight .ow { color: #6ab825; font-weight: bold } /* Operator.Word */ +:root[data-theme="dark"] .highlight .w { color: #666666; } /* Text.Whitespace */ +:root[data-theme="dark"] .highlight .mf { color: #7fb1d7; } /* Literal.Number.Float */ +:root[data-theme="dark"] .highlight .mh { color: #7fb1d7; } /* Literal.Number.Hex */ +:root[data-theme="dark"] .highlight .mi { color: #7fb1d7; } /* Literal.Number.Integer */ +:root[data-theme="dark"] .highlight .mo { color: #7fb1d7; } /* Literal.Number.Oct */ +:root[data-theme="dark"] .highlight .sb { color: #ed9d13; } /* Literal.String.Backtick */ +:root[data-theme="dark"] .highlight .sc { color: #ed9d13; } /* Literal.String.Char */ +:root[data-theme="dark"] .highlight .sd { color: #ed9d13; } /* Literal.String.Doc */ +:root[data-theme="dark"] .highlight .s2 { color: #ed9d13; } /* Literal.String.Double */ +:root[data-theme="dark"] .highlight .se { color: #ed9d13; } /* Literal.String.Escape */ +:root[data-theme="dark"] .highlight .sh { color: #ed9d13; } /* Literal.String.Heredoc */ +:root[data-theme="dark"] .highlight .si { color: #ed9d13; } /* Literal.String.Interpol */ +:root[data-theme="dark"] .highlight .sx { color: #ffa500; } /* Literal.String.Other */ +:root[data-theme="dark"] .highlight .sr { color: #ed9d13; } /* Literal.String.Regex */ +:root[data-theme="dark"] .highlight .s1 { color: #ed9d13; } /* Literal.String.Single */ +:root[data-theme="dark"] .highlight .ss { color: #ed9d13; } /* Literal.String.Symbol */ +:root[data-theme="dark"] .highlight .bp { color: #29a5b3; } /* Name.Builtin.Pseudo */ +:root[data-theme="dark"] .highlight .vc { color: #40ffff; } /* Name.Variable.Class */ +:root[data-theme="dark"] .highlight .vg { color: #40ffff; } /* Name.Variable.Global */ +:root[data-theme="dark"] .highlight .vi { color: #40ffff; } /* Name.Variable.Instance */ +:root[data-theme="dark"] .highlight .il { color: #7fb1d7; } /* Literal.Number.Integer.Long */ diff --git a/docs/_static/copy.js b/docs/_static/copy.js new file mode 100644 index 00000000..f70e3d67 --- /dev/null +++ b/docs/_static/copy.js @@ -0,0 +1,34 @@ +const COPY = "content_copy"; +const COPIED = "done"; + +const copy = async (obj) => { + // {{text}} + await navigator.clipboard.writeText(obj.children[1].innerText).then( + () => { + let icon = obj.children[0].children[0]; + icon.textContent = COPIED; + setTimeout(() => (icon.textContent = COPY), 2500); + }, + (r) => alert('Could not copy codeblock:\n' + r.toString()) + ); +}; + +document.addEventListener("DOMContentLoaded", () => { + let allCodeblocks = document.querySelectorAll("div[class='highlight']"); + + for (let codeblock of allCodeblocks) { + codeblock.parentNode.className += " relative-copy"; + let copyEl = document.createElement("span"); + copyEl.addEventListener('click', () => copy(codeblock)); + copyEl.className = "copy"; + copyEl.setAttribute("aria-label", "Copy Code"); + copyEl.setAttribute("title", "Copy Code"); + + let copyIcon = document.createElement("span"); + copyIcon.className = "material-icons"; + copyIcon.textContent = COPY; + copyEl.append(copyIcon); + + codeblock.prepend(copyEl); + } +}); diff --git a/docs/_static/custom.js b/docs/_static/custom.js index 235a14ea..1274b405 100644 --- a/docs/_static/custom.js +++ b/docs/_static/custom.js @@ -1,31 +1,85 @@ -$(document).ready(function () { - var sections = $('div.section'); - var activeLink = null; - var bottomHeightThreshold = $(document).height() - 30; +'use-strict'; - $(window).scroll(function (event) { - var distanceFromTop = $(this).scrollTop(); - var currentSection = null; +let activeModal = null; +let bottomHeightThreshold, sections; +let hamburgerToggle; +let mobileSearch; +let sidebar; - if(distanceFromTop + window.innerHeight > bottomHeightThreshold) { - currentSection = $(sections[sections.length - 1]); - } - else { - sections.each(function () { - var section = $(this); - if (section.offset().top - 1 < distanceFromTop) { - currentSection = section; - } - }); - } +class Modal { + constructor(element) { + this.element = element; + } - if (activeLink) { - activeLink.parent().removeClass('active'); - } + close() { + activeModal = null; + this.element.style.display = 'none' + } - if (currentSection) { - activeLink = $('.sphinxsidebar a[href="#' + currentSection.attr('id') + '"]'); - activeLink.parent().addClass('active'); + open() { + if (activeModal) { + activeModal.close(); } + activeModal = this; + this.element.style.display = 'flex' + } +} + +class SearchBar { + + constructor() { + this.box = document.querySelector('nav.mobile-only'); + this.bar = document.querySelector('nav.mobile-only input[type="search"]'); + this.openButton = document.getElementById('open-search'); + this.closeButton = document.getElementById('close-search'); + } + + open() { + this.openButton.hidden = true; + this.closeButton.hidden = false; + this.box.style.top = "100%"; + this.bar.focus(); + } + + close() { + this.openButton.hidden = false; + this.closeButton.hidden = true; + this.box.style.top = "0"; + } + +} + +document.addEventListener('DOMContentLoaded', () => { + mobileSearch = new SearchBar(); + + bottomHeightThreshold = document.documentElement.scrollHeight - 30; + sections = document.querySelectorAll('section'); + hamburgerToggle = document.getElementById('hamburger-toggle'); + + if (hamburgerToggle) { + hamburgerToggle.addEventListener('click', (e) => { + sidebar.element.classList.toggle('sidebar-toggle'); + let button = hamburgerToggle.firstElementChild; + if (button.textContent == 'menu') { + button.textContent = 'close'; + } + else { + button.textContent = 'menu'; + } + }); + } + + const tables = document.querySelectorAll('.py-attribute-table[data-move-to-id]'); + tables.forEach(table => { + let element = document.getElementById(table.getAttribute('data-move-to-id')); + let parent = element.parentNode; + // insert ourselves after the element + parent.insertBefore(table, element.nextSibling); }); }); + +document.addEventListener('keydown', (event) => { + if (event.code == "Escape" && activeModal) { + activeModal.close(); + } +}); diff --git a/docs/_static/icons.css b/docs/_static/icons.css new file mode 100644 index 00000000..b237f109 --- /dev/null +++ b/docs/_static/icons.css @@ -0,0 +1,10 @@ +@font-face { + font-family: 'Custom Icons'; + font-style: normal; + font-weight: 400; + src: url('icons.woff') format('woff2'); +} + +.custom-icons { + font-family: 'Custom Icons' !important; +} diff --git a/docs/_static/icons.woff b/docs/_static/icons.woff new file mode 100644 index 00000000..50a340c4 Binary files /dev/null and b/docs/_static/icons.woff differ diff --git a/docs/_static/scorer.js b/docs/_static/scorer.js index 7e00f1d9..f9f95cfe 100644 --- a/docs/_static/scorer.js +++ b/docs/_static/scorer.js @@ -1,17 +1,20 @@ -var _queryBeingDone = null; -var _pattern = null; -var _escapedRegex = /[-\/\\^$*+?.()|[\]{}]/g; +'use-strict'; + +let queryBeingDone = null; +let pattern = null; + +const escapedRegex = /[-\/\\^$*+?.()|[\]{}]/g; function escapeRegex(e) { - return e.replace(_escapedRegex, '\\$&'); + return e.replace(escapedRegex, '\\$&'); } // for some reason Sphinx shows some entries twice // if something has been scored already I'd rather sort it to the bottom -var _beenScored = new Set(); +const beenScored = new Set(); function __score(haystack, regex) { let match = regex.exec(haystack); - if(match == null) { + if (match == null) { return Number.MAX_VALUE; } let subLength = match[0].length; @@ -24,38 +27,41 @@ function __cleanNamespaces(query) { return query.replace(/(discord\.(ext\.)?)?(.+)/, '$3'); } -var Scorer = { +Scorer = { + // Implement the following function to further tweak the score for each result // The function takes a result array [filename, title, anchor, descr, score] // and returns the new score. + score: (result) => { + // only inflate the score of things that are actual API reference things + const [, title, , , score] = result; - score: function(result) { - // only inflate the score of things that are actual API reference things - if(_pattern !== null && result[1].startsWith('discord.')) { - let _score = __score(result[1], _pattern); - if(_score === Number.MAX_VALUE) { - return result[4]; + if (pattern !== null && title.startsWith('discord.')) { + let _score = __score(title, pattern); + if (_score === Number.MAX_VALUE) { + return score; + } + if (beenScored.has(title)) { + return 0; + } + beenScored.add(title); + let newScore = 100 + queryBeingDone.length - _score; + // console.log(`${title}: ${score} -> ${newScore} (${_score})`); + return newScore; } - if(_beenScored.has(result[1])) { - return 0; - } - _beenScored.add(result[1]); - let newScore = 100 + _queryBeingDone.length - _score; - // console.log(`${result[1]}: ${result[4]} -> ${newScore} (${_score})`); - return newScore; - } - return result[4]; + return score; }, - // query matches the full name of an object objNameMatch: 15, // or matches in the last dotted part of the object name objPartialMatch: 11, // Additive scores depending on the priority of the object - objPrio: {0: 15, // used to be importantResults - 1: 7, // used to be objectResults - 2: -5}, // used to be unimportantResults + objPrio: { + 0: 15, // used to be importantResults + 1: 7, // used to be objectResults + 2: -5 // used to be unimportantResults + }, // Used when the priority is not in the mapping. objPrioDefault: 0, @@ -67,12 +73,11 @@ var Scorer = { partialTerm: 2 }; - -$(document).ready(function() { - let params = $.getQueryParameters(); - if(params.q) { - _queryBeingDone = params.q[0]; - let pattern = Array.from(_queryBeingDone).map(escapeRegex).join('.*?'); - _pattern = new RegExp(pattern, 'i'); +document.addEventListener('DOMContentLoaded', () => { + const params = new URLSearchParams(window.location.search); + queryBeingDone = params.get('q'); + if (queryBeingDone) { + let pattern = Array.from(queryBeingDone).map(escapeRegex).join('.*?'); + pattern = new RegExp(pattern, 'i'); } }); diff --git a/docs/_static/settings.js b/docs/_static/settings.js new file mode 100644 index 00000000..9944b1bf --- /dev/null +++ b/docs/_static/settings.js @@ -0,0 +1,103 @@ +'use-strict'; + +let settingsModal; + +class Setting { + constructor(name, defaultValue, setter) { + this.name = name; + this.defaultValue = defaultValue; + this.setValue = setter; + } + + setElement() { + throw new TypeError('Abstract methods should be implemented.'); + } + + load() { + let value = JSON.parse(localStorage.getItem(this.name)); + this.value = value === null ? this.defaultValue : value; + try { + this.setValue(this.value); + } catch (error) { + console.error(`Failed to apply setting "${this.name}" With value:`, this.value); + console.error(error); + } + } + + update() { + throw new TypeError('Abstract methods should be implemented.'); + } + +} + +class CheckboxSetting extends Setting { + + setElement() { + let element = document.querySelector(`input[name=${this.name}]`); + element.checked = this.value; + } + + update(element) { + localStorage.setItem(this.name, element.checked); + this.setValue(element.checked); + } + +} + +class RadioSetting extends Setting { + + setElement() { + let element = document.querySelector(`input[name=${this.name}][value=${this.value}]`); + element.checked = true; + } + + update(element) { + localStorage.setItem(this.name, `"${element.value}"`); + this.setValue(element.value); + } + +} + +function getRootAttributeToggle(attributeName, valueName) { + function toggleRootAttribute(set) { + if (set) { + document.documentElement.setAttribute(`data-${attributeName}`, valueName); + } else { + document.documentElement.removeAttribute(`data-${attributeName}`); + } + } + return toggleRootAttribute; +} + +function setTheme(value) { + if (value === 'automatic') { + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + document.documentElement.setAttribute('data-theme', 'dark'); + } else { + document.documentElement.setAttribute('data-theme', 'light'); + } + } + else { + document.documentElement.setAttribute('data-theme', value); + } +} + +const settings = [ + new CheckboxSetting('useSerifFont', false, getRootAttributeToggle('font', 'serif')), + new RadioSetting('setTheme', 'automatic', setTheme) +] + +function updateSetting(element) { + let setting = settings.find((s) => s.name == element.name); + if (setting) { + setting.update(element); + } +} + +document.addEventListener('DOMContentLoaded', () => { + settingsModal = new Modal(document.querySelector('div#settings.modal')); + for (const setting of settings) { + setting.load(); + setting.setElement(); + } +}); diff --git a/docs/_static/sidebar.js b/docs/_static/sidebar.js new file mode 100644 index 00000000..d9291a26 --- /dev/null +++ b/docs/_static/sidebar.js @@ -0,0 +1,127 @@ +class Sidebar { + constructor(element) { + this.element = element; + this.activeLink = null; + + this.element.addEventListener('click', (e) => { + // If we click a navigation, close the hamburger menu + if (e.target.tagName == 'A' && this.element.classList.contains('sidebar-toggle')) { + this.element.classList.remove('sidebar-toggle'); + let button = hamburgerToggle.firstElementChild; + button.textContent = 'menu'; + + // Scroll a little up to actually see the header + // Note: this is generally around ~55px + // A proper solution is getComputedStyle but it can be slow + // Instead let's just rely on this quirk and call it a day + // This has to be done after the browser actually processes + // the section movement + setTimeout(() => window.scrollBy(0, -100), 75); + } + }); + } + + createCollapsableSections() { + let toc = this.element.querySelector('ul'); + if (!toc) { + return + } + let allReferences = toc.querySelectorAll('a.reference.internal:not([href="#"])'); + + for (let ref of allReferences) { + + let next = ref.nextElementSibling; + + if (next && next.tagName === "UL") { + + let icon = document.createElement('span'); + icon.className = 'material-icons collapsible-arrow expanded'; + icon.innerText = 'expand_more'; + + if (next.parentElement.tagName == "LI") { + next.parentElement.classList.add('no-list-style') + } + + icon.addEventListener('click', () => { + if (icon.classList.contains('expanded')) { + this.collapseSection(icon); + } else { + this.expandSection(icon); + } + }) + + ref.classList.add('ref-internal-padding') + ref.parentNode.insertBefore(icon, ref); + } + } + } + + resize() { + let rect = this.element.getBoundingClientRect(); + this.element.style.height = `calc(100vh - 1em - ${rect.top + document.body.offsetTop}px)`; + } + + collapseSection(icon) { + icon.classList.remove('expanded'); + icon.classList.add('collapsed'); + let children = icon.nextElementSibling.nextElementSibling; + // + // --> + setTimeout(() => children.style.display = "none", 75) + } + + expandSection(icon) { + icon.classList.remove('collapse'); + icon.classList.add('expanded'); + let children = icon.nextElementSibling.nextElementSibling; + setTimeout(() => children.style.display = "block", 75) + } + + setActiveLink(section) { + if (this.activeLink) { + this.activeLink.parentElement.classList.remove('active'); + } + if (section) { + this.activeLink = document.querySelector(`#sidebar a[href="#${section.id}"]`); + if (this.activeLink) { + let headingChildren = this.activeLink.parentElement.parentElement; + let heading = headingChildren.previousElementSibling.previousElementSibling; + + if (heading && headingChildren.style.display === 'none') { + this.activeLink = heading; + } + this.activeLink.parentElement.classList.add('active'); + } + } + } + +} + +function getCurrentSection() { + let currentSection; + if (window.scrollY + window.innerHeight > bottomHeightThreshold) { + currentSection = sections[sections.length - 1]; + } + else { + if (sections) { + sections.forEach(section => { + let rect = section.getBoundingClientRect(); + if (rect.top + document.body.offsetTop < 1) { + currentSection = section; + } + }); + } + } + return currentSection; +} + +document.addEventListener('DOMContentLoaded', () => { + sidebar = new Sidebar(document.getElementById('sidebar')); + sidebar.resize(); + sidebar.createCollapsableSections(); + + window.addEventListener('scroll', () => { + sidebar.setActiveLink(getCurrentSection()); + sidebar.resize(); + }); +}); diff --git a/docs/_static/style.css b/docs/_static/style.css index 43966db8..f0bf4f14 100644 --- a/docs/_static/style.css +++ b/docs/_static/style.css @@ -1,254 +1,722 @@ -/* this stuff uses a couple of themes as a base with some custom stuff added - -In particular thanks to: - +/* +This theme was created from scratch. +Historically however, thanks to: - Alabaster for being a good base - Which thanks Flask + KR theme - Sphinx Readable Theme - Which also proved to be a great base */ -@import url('basic.css'); +/* + note: this CSS is "mobile first" + The desktop implementation is near the bottom +*/ + +* { + box-sizing: border-box; +} + +/* CSS variables would go here */ +:root { + --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + + /* palette goes here */ + --white: #ffffff; + --grey-1: #f9f9fa; + --grey-1-8: rgba(249, 249, 250, 0.8); + --grey-2: #ededf0; + --grey-3: #d7d7db; + --grey-4: #b1b1b3; + --grey-5: #737373; + --grey-6: #4a4a4f; + --grey-7: #38383d; + --grey-8: #2a2a2e; + --black: #0c0c0d; + + --blue-1: #3399ff; + --blue-2: #0a84ff; + --blue-3: #0060df; + --blue-4: #003eaa; + --blue-5: #002275; + --blue-6: #000f40; + + --settings: var(--grey-1); + --settings-hover: var(--grey-1-8); + --main-background: var(--grey-1); + --link-text: var(--blue-2); + --link-hover-text: var(--blue-6); + --main-text: var(--black); + --mobile-nav-background: var(--black); + --mobile-nav-text: var(--white); + --mobile-nav-hover-text: var(--white); + --mobile-nav-header-text: var(--white); + --nav-background: var(--main-background); + --nav-text: var(--grey-6); + --nav-hover-text: var(--grey-6); + --nav-header-text: var(--black); + --sub-header-background: var(--grey-6); + --search-border: var(--grey-4); + --search-text: var(--white); + --search-focus: var(--blue-1); + --search-button: var(--grey-1); + --search-button-hover: var(--grey-1-8); + --footer-text: var(--grey-5); + --footer-link: var(--grey-6); + --hr-border: var(--grey-2); + --main-big-headers-text: var(--black); + --main-big-headers-border: var(--grey-4); + --main-h5-header-text: var(--black); + --main-h6-header-text: var(--grey-4); + --main-h4-header-border: var(--grey-4); + --header-link: var(--grey-6); + --header-link-hover-text: var(--white); + --admonition-background: var(--grey-2); + --note-background: var(--blue-1); + --note-text: var(--white); + --warning-background: #ffe900; + --warning-text: var(--black); + --error-background: #d70022; + --error-text: var(--white); + --helpful-background: #00c8d7; + --helpful-text: var(--black); + --codeblock-background: var(--grey-2); + --codeblock-border: var(--grey-4); + --codeblock-text: var(--grey-6); + --inline-code-background: var(--grey-3); + --xref-code-background: transparent; + --api-entry-background: var(--grey-2); + --table-header-background: var(--grey-3); + --table-text: var(--black); + --table-border: var(--grey-4); + --mobile-active-toc: var(--grey-7); + --active-toc: var(--grey-3); + --scrollbar: rgba(0,0,0,0.2); + --scrollbar-hover: rgba(0,0,0,0.4); + --rtd-ad-border: var(--grey-3); + --rtd-ad-background: var(--grey-2); + --rtd-ad-main-text: var(--grey-6); + --rtd-ad-small-text: var(--grey-4); + --attribute-table-title: var(--grey-6); + --attribute-table-entry-border: var(--grey-3); + --attribute-table-entry-text: var(--grey-5); + --attribute-table-entry-hover-border: var(--blue-2); + --attribute-table-entry-hover-background: var(--grey-2); + --attribute-table-entry-hover-text: var(--blue-2); + --attribute-table-badge: var(--grey-7); +} + +:root[data-font="serif"] { + --font-family: 'Georgia', 'Yu Gothic', 'Noto Sans CJK JP Regular', serif; +} + +:root[data-theme="dark"] { + --main-background: var(--grey-7); + --link-text: var(--blue-1); + --link-hover-text: var(--blue-2); + --main-text: var(--white); + --sub-header-background: var(--grey-8); + --search-border: var(--grey-5); + --nav-background: var(--main-background); + --nav-text: var(--grey-1); + --nav-hover-text: var(--grey-2); + --nav-header-text: var(--white); + --footer-text: var(--grey-2); + --footer-link: var(--grey-1); + --hr-border: var(--grey-1); + --main-big-headers-text: var(--grey-1); + --main-big-headers-border: var(--grey-1); + --main-h5-header-text: var(--grey-4); + --main-h6-header-text: var(--grey-5); + --main-h4-header-border: var(--grey-2); + --header-link: var(--grey-2); + --header-link-hover-text: var(--grey-6); + --admonition-background: var(--grey-8); + --note-background: var(--blue-3); + --note-text: var(--white); + --warning-background: #d7b600; + --warning-text: var(--black); + --error-background: #d70022; + --error-text: var(--white); + --helpful-background: #008ea4; + --helpful-text: var(--white); + --codeblock-background: var(--grey-6); + --codeblock-border: var(--black); + --codeblock-text: var(--grey-1); + --inline-code-background: var(--grey-8); + --xref-code-background: transparent; + --api-entry-background: var(--grey-6); + --table-header-background: var(--grey-6); + --table-text: var(--grey-1); + --table-border: var(--grey-4); + --active-toc: var(--grey-6); + --scrollbar: rgba(0,0,0,0.5); + --scrollbar-hover: rgba(0,0,0,0.7); + --rtd-ad-border: var(--grey-6); + --rtd-ad-background: var(--grey-5); + --rtd-ad-main-text: var(--grey-2); + --rtd-ad-small-text: var(--grey-1); + --attribute-table-title: var(--grey-3); + --attribute-table-entry-border: var(--grey-5); + --attribute-table-entry-text: var(--grey-3); + --attribute-table-entry-hover-border: var(--blue-1); + --attribute-table-entry-hover-background: var(--grey-6); + --attribute-table-entry-hover-text: var(--blue-1); + --attribute-table-badge: var(--grey-4); +} + +img[src$="snake_dark.svg"] { + display: none; +} +:root[data-theme="dark"] img[src$="snake.svg"] { + display: none; +} +:root[data-theme="dark"] img[src$="snake_dark.svg"] { + display: inherit; +} body { - font-family: 'Georgia', 'Yu Gothic', 'Noto Sans CJK JP Regular', serif; + font-family: var(--font-family); font-size: 16px; margin: 0; padding: 0; + height: 100%; + background-color: var(--main-background); + color: var(--main-text); +} + + +/* Scrollbar related */ + +#sidebar::-webkit-scrollbar { + width: 0.5em; +} + +#sidebar::-webkit-scrollbar-thumb { + background-color: var(--scrollbar); + border-radius: 0.25em; +} + +#sidebar::-webkit-scrollbar-thumb:hover { + background-color: var(--scrollbar-hover); +} + + +/* grid related */ + +.main-grid { + display: grid; + min-height: 100%; + grid-auto-rows: min-content auto min-content; + grid-template-areas: + "s" + "h" + "n" + "c" + "f"; +} + +.grid-item { + max-width: 100vw; + padding: 0.8em; +} + +/* all URLs only show underline on hover */ +a { + text-decoration: none; + color: var(--link-text); +} + +a:hover { + text-decoration: underline; + color: var(--link-hover-text); +} + +/* headers */ + +header.grid-item { + grid-area: h; + color: var(--main-text); + position: relative; + z-index: 1; + padding: 0; +} + +header > nav { + background-color: var(--sub-header-background); + padding: 0.8em; + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +header > nav a { + color: var(--white); +} + +header > nav.mobile-only { + width: 100%; + position: absolute; + top: 0; + right: 0; + z-index: -1; + padding-top: 0; + transition: top 0.5s ease-in-out; +} + +header > nav.mobile-only .search { + width: 100%; +} + +header > nav.mobile-only .search-wrapper { + background-color: var(--sub-header-background); +} + +.main-heading { + margin-right: auto; +} + +header > nav a:not(.main-heading) { + margin: 0 0.5em; +} + +header > nav > a:hover { + color: var(--grey-1-8); + text-decoration: underline; +} + +.sub-header { + grid-area: n; + background-color: var(--sub-header-background); + color: var(--white); + display: none; +} + +/* these aren't shown on mobile */ + +.sub-header > label { + display: none; + margin-right: 1em; +} + +.sub-header > select { + display: none; + background-color: transparent; + padding: 0.4em 0; + font-size: 1em; + width: 13.5%; + color: white; + border: none; + border-bottom: 1px solid var(--search-border); + + appearance: none; + background-image: url('/_images/drop_down_icon.svg'); + background-repeat: no-repeat; + background-position-x: 100%; + background-position-y: 50%; + + cursor: pointer; +} +.sub-header > select:focus { + outline: none; +} + +.sub-header > .settings { + color: var(--settings); + display: none; + margin-left: 1em; + margin-right: 0.5em; +} + +.setting h3 { + display: inline-block; + margin-left: 2em; +} + +.sub-header > .settings:hover { + color: var(--settings-hover); +} + +/* footer stuff */ +footer { + grid-area: f; + font-size: 14px; + text-align: right; + color: var(--footer-text); +} + +footer a { + text-decoration: underline; + color: var(--footer-link); +} + +/* sidebar stuff */ + +aside { + grid-area: s; + font-size: 14px; + line-height: 1.75em; + top: 0; + position: -webkit-sticky; /* safari */ + position: sticky; + background-color: var(--mobile-nav-background); + color: var(--mobile-nav-text); + z-index: 2; + max-height: 100vh; + overflow-y: auto; + overscroll-behavior-y: contain; +} + +aside h3 { + color: var(--mobile-nav-header-text); + font-size: 24px; + font-weight: normal; +} + +.collapsible-arrow { + font-size: 1.5em!important; + left: -1.166em; + top: 0.25em; + user-select: none; + position: relative; + line-height: 0.5em; + transition: transform 0.4s; + transform: rotate(0deg); +} + +.expanded { + transition: transform 0.4s; + transform: rotate(-90deg); +} + +.ref-internal-padding { + position: relative; + left: -20px; +} + +#settings-toggle { + float: right; +} + +aside .material-icons, +.settings > .material-icons { + cursor: pointer; + font-size: 2em; +} + +.sidebar-toggle { + display: unset !important; +} + +#sidebar { + display: none; +} + +#sidebar a { + color: var(--mobile-nav-text); +} + +#sidebar a:hover { + color: var(--mobile-nav-hover-text); +} + +#sidebar h3 { + font-size: 24px; + margin: 1em 1em 0 0; +} + +#sidebar ul { + list-style: none; + margin: 1em 2em 2em 1em; + padding: 0; +} + +#sidebar ul ul { + list-style: square; + margin: 0em; + margin-left: 1.5em; +} + +#sidebar li.no-list-style { + list-style: none; +} + +#sidebar form { + margin: 1em 0; + display: flex; + align-items: baseline; +} + +/* search button stuff */ + +.search-wrapper { + display: flex; + align-items: stretch; +} + +.search-wrapper > input[type=search] { + font-family: "Roboto", Corbel, Avenir, "Lucida Grande", "Lucida Sans", sans-serif; + outline: none; + appearance: none; + font-size: 1em; +} + +.search-wrapper > input[type=search], +.search-wrapper > button[type=submit] { + background-color: var(--sub-header-background); + border: none; + color: var(--search-text); + padding: 0.5em; + min-height: 2.5em; + flex: 9; +} + +.search-wrapper { + border-bottom: 1px solid var(--search-border); +} + +.search-wrapper:focus-within { + border-bottom: 1px solid var(--search-focus); +} + +/* .search-wrapper > input[type=search] { + border: 1px solid var(--search-border); + border-right: none; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.search-wrapper > input[type=search]:focus, +button[type=submit]:focus ~ input[type=search] { + border: 1px solid var(--search-focus); + border-right: none; +} */ + +.search-wrapper > button[type=submit] { + color: var(--search-button); + /* border: 1px solid var(--search-border); */ + /* border-left: none; */ + /* border-bottom-right-radius: 4px; */ + /* border-top-right-radius: 4px; */ + cursor: pointer; + flex: 1; +} + +/* .search-wrapper > button[type=submit]:focus, +input[type=search]:focus ~ button[type=submit] { + border: 1px solid var(--search-focus); + border-left: none; +} */ + +.search-wrapper > button[type=submit]:hover { + background-color: var(--search-border); + color: var(--search-button-hover); +} + +/* main content area */ + +main { + grid-area: c; } p { margin-bottom: 8px; } -div.document { - margin: 10px auto 0 auto; - max-width: 1200px; /* page width */ -} +/* modal stuff */ -div.body { - max-width: 960px; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 240px; /* sidebar width */ -} - -div.body { - background-color: #ffffff; - color: #3e4349; - padding: 0 30px 30px 30px; -} - -div.footer { - color: #555; - font-size: 14px; - margin: 20px auto 30px auto; - text-align: right; - max-width: 1200px; /* page width */ -} - -div.footer a { - color: #444; - text-decoration: underline; -} - -div.related { - padding: 10px 10px; - width: auto; -} - -div.sphinxsidebar { - float: left; - font-size: 14px; - line-height: 1.5em; - margin-left: -100%; - width: 240px; /* sidebar width */ -} - -div.sphinxsidebarwrapper { - font-size: 14px; - line-height: 1.5em; - padding: 10px 0 10px 10px; - - /* sticky sidebar */ +div.modal { position: fixed; - width: 240px; /* sidebar width */ - height: 90%; + z-index: 10; + left: 0; + top: 0; + width: 100%; + height: 100%; overflow: hidden; + background-color: rgba(0,0,0,0.4); + cursor: pointer; + display: none; } -/* show scrollbar on hover */ -div.sphinxsidebarwrapper:hover { - overflow: auto; +div.modal-content { + background-color: var(--main-background); + box-shadow: 0 2px 8px rgba(0,0,0,0.54); + padding: 24px; + border-radius: 4px; + max-width: 40%; + min-width: 350px; + cursor: initial; + flex: 1; + margin: auto; } -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - color: #333; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 1.1em; -} - -div.sphinxsidebar h3 a { - color: #333; -} - -div.sphinxsidebar p { +div.modal-content > span.close { color: #888; + float: right; + font-weight: bold; + -moz-user-select: none; + -webkit-user-select: none; + cursor: pointer; } -div.sphinxsidebar p.searchtip { - line-height: 1.4em; -} - -div.sphinxsidebar ul { - color: #000; - margin: 10px 0 20px; - padding: 0; -} - -div.sphinxsidebar a { +div.modal-content > span.close:hover, +div.modal-content > span.close:focus { color: #444; } -div.sphinxsidebar input { - border: 1px solid #ccc; - font-family: sans-serif; - font-size: 1em; - margin-top: 10px; +div.modal input { + cursor: pointer; +} + +/* copy button */ + +.relative-copy { + position: relative; +} + +.copy { + cursor: pointer; + position: absolute; + top: 0px; + right: 0px; + border: 1px solid var(--codeblock-border); + font-size: 0.875em; + padding: 0.2em 0.5em; + border-bottom-left-radius: 4px; + display: flex; } /* -- body styles --------------------------------------------------------- */ -a { - color: #2591c4; - text-decoration: none; -} - -a:hover { - color: #0b3a44; - text-decoration: underline; -} - hr { - border: 1px solid #b1b4b6; + border: 1px solid var(--hr-border); } -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { font-weight: normal; } +main h1, +main h2, +main h3, +main h4, +main h5, +main h6 { font-weight: normal; } -div.body h1, -div.body h2, -div.body h3, -div.body h4 { color: #212224; } -div.body h5 { color: #000; } -div.body h6 { color: #777; } +main h1, +main h2, +main h3, +main h4 { color: var(--main-big-headers-text); } +main h5 { color: var(--main-h5-header-text); } +main h6 { color: var(--main-h6-header-text); } -div.body h1 { margin: 0 0 10px 0; } -div.body h2, -div.body h3 { margin: 10px 0px 10px 0px; } -div.body h4, -div.body h5, -div.body h6 { margin: 20px 0px 10px 0px; } +main h1 { margin: 0 0 10px 0; } +main h2, +main h3 { margin: 10px 0px 10px 0px; } +main h4, +main h5, +main h6 { margin: 20px 0px 10px 0px; } -div.body h1 { padding: 0 0 10px 0; } -div.body h2, -div.body h3 { padding: 10px 0 10px 0; } -div.body h4 { padding: 10px 0 10px 0; } -div.body h5, -div.body h6 { padding: 10px 0 0 0; } +main h1 { padding: 0 0 10px 0; } +main h2, +main h3 { padding: 10px 0 10px 0; } +main h4 { padding: 10px 0 10px 0; } +main h5, +main h6 { padding: 10px 0 0 0; } -div.body h1, -div.body h2, -div.body h3 { border-bottom: 1px solid #ddd; } -div.body h4 { border-bottom: 1px solid #e5e5e5; } +main h1, +main h2, +main h3 { border-bottom: 1px solid var(--main-big-headers-border); } +main h4 { border-bottom: 1px solid var(--main-h4-header-border); } -div.body h1 { font-size: 230%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 130%; } -div.body h4 { font-size: 110%; } -div.body h5 { font-size: 105%; } -div.body h6 { font-size: 100%; } +main h1 { font-size: 2.3em; } +main h2 { font-size: 1.8em; } +main h3 { font-size: 1.3em; } +main h4 { font-size: 1.1em; } +main h5 { font-size: 1.05em; } +main h6 { font-size: 1em; } a.headerlink { - color: #3e4349; + color: var(--header-link); font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; + visibility: hidden; } a.headerlink:hover { - background-color: #3e4349; - color: #fff; + background-color: var(--header-link); + color: var(--header-link-hover-text); } -div.body ul { +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +.versionmodified { + font-style: italic; +} + +main ul { list-style: disc; margin: 1em 0; padding-left: 1.3em; } -div.body ul ul, div.body ol ul { +main ul ul, main ol ul { margin: .2em 0; padding-left: 1.2em; } -div.body ul li { +main ul li { padding: 2px 0; } -div.body ul.search li { +main ul.search li { padding: 5px 0 5px 20px; } -div.body ol { +main ol { counter-reset: li; margin-left: 0; padding-left: 0; } -div.body ol ol { +main ol ol { margin: .2em 0; } -div.body ol > li { +main ol > li { list-style: none; margin: 0 0 0 1.9em; padding: 2px 1px; position: relative; } -div.body ol > li:before { +main ol > li::before { content: counter(li) "."; counter-increment: li; top: -2px; - left: -1.9em; - width: 1.9em; + left: -1.1em; + width: 1.1em; padding: 4px 0; position: absolute; text-align: left; } -div.body p, -div.body dd, -div.body li { - line-height: 1.4em; +main p, +main dd, +main li { + line-height: 1.4; +} + +main img { + width: 100%; + max-width: 500px; } /* weird margins */ @@ -260,22 +728,106 @@ li > blockquote { margin: 10px; } -div.admonition p.admonition-title + p { - display: inline; +/* admonitions */ +div.admonition { + padding: 0 0.8em; + padding-bottom: 0.8em; + margin: 0.8em 0; + border-radius: 2.5px; + border-left-width: 6px; + border-left-style: solid; + background-color: var(--admonition-background); } -div.highlight { - background-color: #fff; +p.admonition-title { + font-weight: bold; + margin: 0 -0.8rem; + padding: 0.4rem 0.6rem 0.4rem 2.5rem; + position: relative; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +p.admonition-title::before { + font: normal normal normal 24px/1 'Material Icons'; + display: inline-block; + width: 24px; + height: 24px; + position: absolute; + left: 9.6px; } div.important, div.note, div.hint, div.tip { - background-color: #eee; - border: 1px solid #ccc; + border-left-color: var(--note-background); } -div.attention, div.warning, div.caution, div.seealso { - background-color: #fef9e9; - border: 1px solid #fbe091; +div.important > p.admonition-title, +div.note > p.admonition-title, +div.hint > p.admonition-title, +div.tip > p.admonition-title { + background-color: var(--note-background); + color: var(--note-text); +} + +div.important > p.admonition-title::before, +div.note > p.admonition-title::before, +div.hint > p.admonition-title::before, +div.tip > p.admonition-title::before { + content: '\0e88e'; +} + +div.attention, div.warning, div.caution { + border-left-color: var(--warning-background); +} + +div.attention > p.admonition-title, +div.warning > p.admonition-title, +div.caution > p.admonition-title { + background-color: var(--warning-background); + color: var(--warning-text); +} + +div.attention > p.admonition-title::before, +div.warning > p.admonition-title::before, +div.caution > p.admonition-title::before { + content: '\0e002'; +} + +div.danger, div.error { + border-left-color: var(--error-background); +} + +div.danger > p.admonition-title, +div.error > p.admonition-title { + background-color: var(--error-background); + color: var(--error-text); +} + +div.danger > p.admonition-title::before, +div.error > p.admonition-title::before { + content: '\0e000'; +} + +/* helpful admonitions */ +div.helpful { + border-left-color: var(--helpful-background); +} + +div.helpful > p.admonition-title { + background-color: var(--helpful-background); + color: var(--helpful-text); +} + +div.helpful > p.admonition-title::before { + content: '\0e873'; +} + +dl.field-list > dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 20px; } /* no disgusting background in the FAQ */ @@ -287,7 +839,7 @@ div.topic { /* don't link-ify the FAQ page */ a.toc-backref { text-decoration: none; - color: #3e4349; + color: var(--main-text); } /* bold and fix the Parameter, Raises, etc. */ @@ -306,37 +858,6 @@ a.reference.internal > strong { font-family: monospace; } -div.danger, div.error { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -div.admonition { - padding: 10px; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ':'; -} - -/* helpful admonitions */ -div.helpful { - background-color: #e4f2ff; - border: 1px solid #66b3ff; -} - -div.helpful > p.admonition-title { - display: block; -} - -div.helpful > p.admonition-title:after { - content: unset; -} - /* exception hierarchy */ .exception-hierarchy-content dd, @@ -352,31 +873,112 @@ div.helpful > p.admonition-title:after { list-style: 'ยป' !important; } +/* attribute tables */ +.py-attribute-table { + display: flex; + flex-wrap: wrap; + flex-direction: row; + margin: 0 2em; + padding-top: 16px; +} + +.py-attribute-table-column { + flex: 1 1 auto; +} + +.py-attribute-table-column:not(:first-child) { + margin-top: 1em; +} + +.py-attribute-table-column > span { + font-weight: bold; + color: var(--attribute-table-title); +} + +main .py-attribute-table-column > ul { + list-style: none; + margin: 4px 0px; + padding-left: 0; + font-size: 0.95em; +} + +.py-attribute-table-entry { + margin: 0; + padding: 2px 0; + padding-left: 0.2em; + border-left: 2px solid var(--attribute-table-entry-border); + display: flex; + line-height: 1.2em; +} + +.py-attribute-table-entry > a { + padding-left: 0.5em; + color: var(--attribute-table-entry-text); + flex-grow: 1; +} + +.py-attribute-table-entry > a:hover { + color: var(--attribute-table-entry-hover-text); + text-decoration: none; +} + +.py-attribute-table-entry:hover { + background-color: var(--attribute-table-entry-hover-background); + border-left: 2px solid var(--attribute-table-entry-hover-border); + text-decoration: none; +} + +.py-attribute-table-badge { + flex-basis: 3em; + text-align: right; + font-size: 0.9em; + color: var(--attribute-table-badge); + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} + pre { - background-color: #f5f5f5; - border: 1px solid #C6C9CB; - color: #222; + background-color: var(--codeblock-background); + border: 1px solid var(--codeblock-border); + color: var(--codeblock-text); font-size: 0.75em; line-height: 1.5em; margin: 1.5em 0 1.5em 0; padding: 10px; + overflow-x: auto; } -pre, tt, code { +pre, code { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.9em; + overflow-wrap: break-word; } -tt, code { - background-color: #ecf0f3; +code { + background-color: var(--inline-code-background); + padding: .15em; + border-radius: 3px; } -tt.descname, code.descname { +code.descname { + background-color: transparent; + font-weight: bold; font-size: 0.95em; } -tt.xref, a tt, code.xref, a code { +code.descclassname { + background-color: transparent; + padding-right: 0; +} + +code.descclassname + code.descname { + padding-left: 0; +} + +code.xref, a code { font-weight: normal; + background-color: var(--xref-code-background); } span.pre { @@ -387,6 +989,7 @@ dl.class { margin-bottom: 50px; } +dl.data > dt, dl.describe > dt, dl.function > dt, dl.attribute > dt, @@ -394,34 +997,41 @@ dl.classmethod > dt, dl.method > dt, dl.class > dt, dl.exception > dt { - background-color: #f5f5f5; + background-color: var(--api-entry-background); padding: 1px 10px; } dd { - margin-top: 10px; + margin-top: 0.5em; + margin-bottom: 0.5em; + margin-left: 1.5em; } .container.operations { padding: 10px; - border: 1px solid #ddd; + border: 1px solid var(--codeblock-border); margin-bottom: 20px; } .container.operations::before { content: 'Supported Operations'; - color: #212224; + color: var(--main-big-headers-text); display: block; - padding-bottom: 5px; + padding-bottom: 0.5em; } .container.operations > dl.describe > dt { - background-color: #f8f8f8; + background-color: var(--api-entry-background); +} + +.table-wrapper { + overflow-x: auto; } table.docutils { width: 100%; + border-collapse: collapse; } table.docutils.footnote { @@ -430,11 +1040,11 @@ table.docutils.footnote { table.docutils thead, table.docutils tfoot { - background: #f5f5f5; + background: var(--table-header-background); } table.docutils thead tr th { - color: #000; + color: var(--table-text); font-weight: normal; padding: 7px 5px; vertical-align: middle; @@ -443,13 +1053,17 @@ table.docutils thead tr th { table.docutils tbody tr th, table.docutils tbody tr td { border-bottom: 0; - border-top: solid 1px #ddd; padding: 7px 5px; vertical-align: top; } + +table.docutils tbody tr:not(:first-child) { + border-top: solid 1px var(--table-border); +} + table.docutils tbody tr:last-child th, table.docutils tbody tr:last-child td { - border-bottom: solid 1px #ddd; + border-bottom: solid 1px var(--table-border); } table.docutils thead tr td p, @@ -475,24 +1089,29 @@ table.docutils tbody tr td ol.last { margin-bottom: 0; } -.viewcode-back { - font-family: Arial, sans-serif; -} - -div.viewcode-block:target { - background-color: #fef9e9; - border-top: 1px solid #fbe091; - border-bottom: 1px solid #fbe091; -} - /* hide the welcome text */ -div#welcome-to-discord-py > h1 { +section#welcome-to-discord-py > h1 { display: none; } +/* make the RTD ad look a little less jarring */ + +.ethical-fixedfooter { + background-color: var(--rtd-ad-background) !important; + border-top: 1px solid var(--rtd-ad-border) !important; +} + +.ethical-fixedfooter a { + color: var(--rtd-ad-main-text) !important; +} + +.ethical-callout > small > em > a { + color: var(--rtd-ad-small-text) !important; +} + .active { - background-color: #dbdbdb; - border-left: 5px solid #dbdbdb; + background-color: var(--mobile-active-toc); + border-left: 5px solid var(--mobile-active-toc); } div.code-block-caption { @@ -500,78 +1119,146 @@ div.code-block-caption { font-weight: bold; } -@media screen and (max-width: 870px) { - div.document { - width: auto; - margin: 0; +/* desktop stuff */ + +@media screen and (min-width: 600px) { + .grid-item { + max-width: unset; } - div.documentwrapper { - float: none; + .main-grid { + grid-template-areas: + "h h h h h h" + "n n n n n n" + "s s c c c c" + "s s f f f f"; } - div.bodywrapper { - margin: 0; + .mobile-only { + display: none; } - div.body { - min-height: 0; - padding: 0 20px 30px 20px; + header { + background-color: var(--black); } - div.footer { - background-color: #333; - color: #888; - margin: 0; - padding: 10px 20px 20px; - text-align: left; - width: auto; + header > nav { + background-color: unset; } - div.footer a { - color: #bbb; + .sub-header { + display: flex; + align-items: center; } - div.footer a:hover { - color: #fff; + .sub-header > label { + display: initial; } - div.sphinxsidebar { - background-color: #333; - color: #fff; - float: none; - margin: 0; - padding: 10px 20px; - width: auto; + .sub-header > select { + display: initial; + margin-right: auto; } - /* sticky sidebar */ - div.sphinxsidebarwrapper { - position: relative; + .sub-header > .settings { + display: initial; } - div.sphinxsidebar h3, - div.sphinxsidebar h4, - div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; + aside { + top: initial; + position: initial; + background-color: var(--nav-background); + color: var(--nav-text); + max-height: unset; + overflow-y: unset; + overscroll-behavior-y: unset; } - div.sphinxsidebar ul { - color: #999; + aside h3 { + color: var(--nav-header-text); } - div.sphinxsidebar a { - color: #aaa; + #sidebar { + display: inline-block; + position: sticky; + top: 1em; + max-height: calc(100vh - 2em); + overflow-y: auto; + margin: 1em; } - div.sphinxsidebar a:hover { - color: #fff; + #sidebar a { + color: var(--nav-text); } .active { background-color: transparent; border-left: none; + position: relative; + } + + .active::before { + content: ""; + display: inline-block; + background-color: var(--active-toc); + position: absolute; + top: 0; + bottom: 0; + right: 0; + width: calc(100% + 0.5em); + border-radius: 4px; + z-index: -1; + } + + #sidebar a:hover { + color: var(--nav-hover-text); + } + + #hamburger-toggle, #settings-toggle { + display: none; + + } +} + +@media screen and (min-width: 1200px) { + .main-grid { + /* 62.5% width => multiple of 5/8 content */ + /* sidebar takes up 20% of the inner area */ + grid-template-columns: repeat(16, 1fr); + grid-template-areas: + "h h h h h h h h h h h h h h h h" + "n n n n n n n n n n n n n n n n" + "s s s . . c c c c c c c c c . ." + "s s s f f f f f f f f f f f f f" + } + + header > nav { + margin-left: 18.75%; + margin-right: 18.75%; + } + + .sub-header > label { + margin-left: 18.75%; + margin-right: 1em; + } + + .sub-header > .settings { + margin-right: 18.75%; + margin-left: 1em; + } + + .sub-header > .search { + width: 20%; + } + + .py-attribute-table-column:not(:first-child) { + margin-top: unset; + } + + main img { + display: block; + margin-left: auto; + margin-right: auto; } } diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index 0ef7d54f..d4571f7c 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -1,40 +1,194 @@ -{%- extends "basic/layout.html" %} - -{% set show_source = False %} -{% set style = 'style.css' %} - -{%- block extrahead %} - {{ super() }} - -{% endblock %} - -{%- block relbar2 %}{% endblock %} - -{% block header %} - {{ super() }} - {% if pagename == 'index' %} -
- {% endif %} -{% endblock %} - - + + + + + + {{ title|striptags|e }}{{ titlesuffix }} + {%- block extrahead %} {% endblock %} + + + + + + {%- block css %} + {%- for css in css_files %} + {%- if css|attr("filename") %} + {{ css_tag(css) }} + {%- else %} + + {%- endif %} + {%- endfor %} + {%- endblock %} + {%- block scripts %} + + {%- for js in script_files %} + {{ js_tag(js) }} + {%- endfor %} + {%- endblock %} + {%- if pageurl %} + + {%- endif %} + {%- if favicon %} + + {%- endif %} + {%- block linktags %} + {%- if hasdoc('about') %} + + {%- endif %} + {%- if hasdoc('genindex') %} + + {%- endif %} + {%- if hasdoc('search') %} + + {%- endif %} + {%- if hasdoc('copyright') %} + + {%- endif %} + {%- if next %} + + {%- endif %} + {%- if prev %} + + {%- endif %} + {%- endblock %} + + +{%- block header %}{% endblock %} +
+ {#- The main navigation header #} +
+ + +
+ {#- The sub-header with search and extension related selection #} +
+ + + + settings +
+ {#- The sidebar component #} + + {#- The actual body of the contents #} +
+ {% block body %} {% endblock %} +
{%- block footer %} - - {% if pagename == 'index' %} -
- {% endif %} - {%- if READTHEDOCS %} + {%- endif %} -{%- endblock %} + + + + + diff --git a/docs/api.rst b/docs/api.rst index d697b4f3..6f232190 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -30,48 +30,108 @@ There are two main ways to query version information about the library. For guar A string representation of the version. e.g. ``'1.0.0rc1'``. This is based off of :pep:`440`. +Clients +-------- + Client -------- +~~~~~~~ + +.. attributetable:: Client .. autoclass:: Client :members: +AutoShardedClient +~~~~~~~~~~~~~~~~~~ + +.. attributetable:: AutoShardedClient + .. autoclass:: AutoShardedClient :members: +Application Info +------------------ + +AppInfo +~~~~~~~~ + +.. attributetable:: AppInfo + .. autoclass:: AppInfo() :members: +Team +~~~~~ + +.. attributetable:: Team + .. autoclass:: Team() :members: +TeamMember +~~~~~~~~~~~ + +.. attributetable:: TeamMember + .. autoclass:: TeamMember() :members: -Voice ------- +Voice Related +--------------- + +VoiceClient +~~~~~~~~~~~~ + +.. attributetable:: VoiceClient .. autoclass:: VoiceClient() :members: -.. autoclass:: VoiceProtocol - :members: +AudioSource +~~~~~~~~~~~~ + +.. attributetable:: AudioSource .. autoclass:: AudioSource :members: +PCMAudio +~~~~~~~~~ + +.. attributetable:: PCMAudio + .. autoclass:: PCMAudio :members: +FFmpegAudio +~~~~~~~~~~~~ + +.. attributetable:: FFmpegAudio + .. autoclass:: FFmpegAudio :members: +FFmpegPCMAudio +~~~~~~~~~~~~~~~ + +.. attributetable:: FFmpegPCMAudio + .. autoclass:: FFmpegPCMAudio :members: +FFmpegOpusAudio +~~~~~~~~~~~~~~~~ + +.. attributetable:: FFmpegOpusAudio + .. autoclass:: FFmpegOpusAudio :members: +PCMVolumeTransformer +~~~~~~~~~~~~~~~~~~~~~ + +.. attributetable:: PCMVolumeTransformer + .. autoclass:: PCMVolumeTransformer :members: @@ -2036,9 +2096,19 @@ Working with :meth:`Guild.audit_logs` is a complicated process with a lot of mac involved. The library attempts to make it easy to use and friendly. In order to accomplish this goal, it must make use of a couple of data classes that aid in this goal. +AuditLogEntry +~~~~~~~~~~~~~~~ + +.. attributetable:: AuditLogEntry + .. autoclass:: AuditLogEntry :members: +AuditLogChanges +~~~~~~~~~~~~~~~~~ + +.. attributetable:: AuditLogChanges + .. class:: AuditLogChanges An audit log change set. @@ -2083,6 +2153,11 @@ this goal, it must make use of a couple of data classes that aid in this goal. | ``None`` | No attributes are set. | +----------------------------------------+--------------------------------------------------+ +AuditLogDiff +~~~~~~~~~~~~~ + +.. attributetable:: AuditLogDiff + .. class:: AuditLogDiff Represents an audit log "change" object. A change object has dynamic @@ -2428,6 +2503,8 @@ Webhook Support discord.py offers support for creating, editing, and executing webhooks through the :class:`Webhook` class. +.. attributetable:: Webhook + .. autoclass:: Webhook :members: @@ -2459,18 +2536,43 @@ They are mainly there for usage with :func:`py:isinstance` and :func:`py:issubcl This library has a module related to abstract base classes, some of which are actually from the :doc:`abc ` standard module, others which are not. +Snowflake +~~~~~~~~~~ + +.. attributetable:: discord.abc.Snowflake + .. autoclass:: discord.abc.Snowflake :members: +User +~~~~~ + +.. attributetable:: discord.abc.User + .. autoclass:: discord.abc.User :members: +PrivateChannel +~~~~~~~~~~~~~~~ + +.. attributetable:: discord.abc.PrivateChannel + .. autoclass:: discord.abc.PrivateChannel :members: +GuildChannel +~~~~~~~~~~~~~ + +.. attributetable:: discord.abc.GuildChannel + .. autoclass:: discord.abc.GuildChannel :members: +Messageable +~~~~~~~~~~~~ + +.. attributetable:: discord.abc.Messageable + .. autoclass:: discord.abc.Messageable :members: :exclude-members: history, typing @@ -2481,6 +2583,11 @@ module, others which are not. .. automethod:: discord.abc.Messageable.typing :async-with: +Connectable +~~~~~~~~~~~~ + +.. attributetable:: discord.abc.Connectable + .. autoclass:: discord.abc.Connectable .. _discord_api_models: @@ -2513,6 +2620,8 @@ the user of the library. ClientUser ~~~~~~~~~~~~ +.. attributetable:: ClientUser + .. autoclass:: ClientUser() :members: :inherited-members: @@ -2520,12 +2629,16 @@ ClientUser Relationship ~~~~~~~~~~~~~~ +.. attributetable:: Relationship + .. autoclass:: Relationship() :members: User ~~~~~ +.. attributetable:: User + .. autoclass:: User() :members: :inherited-members: @@ -2540,24 +2653,32 @@ User Attachment ~~~~~~~~~~~ +.. attributetable:: Attachment + .. autoclass:: Attachment() :members: Asset ~~~~~ +.. attributetable:: Asset + .. autoclass:: Asset() :members: Message ~~~~~~~ +.. attributetable:: Message + .. autoclass:: Message() :members: Reaction ~~~~~~~~~ +.. attributetable:: Reaction + .. autoclass:: Reaction() :members: :exclude-members: users @@ -2568,18 +2689,24 @@ Reaction CallMessage ~~~~~~~~~~~~ +.. attributetable:: CallMessage + .. autoclass:: CallMessage() :members: GroupCall ~~~~~~~~~~ +.. attributetable:: GroupCall + .. autoclass:: GroupCall() :members: Guild ~~~~~~ +.. attributetable:: Guild + .. autoclass:: Guild() :members: :exclude-members: audit_logs @@ -2599,6 +2726,8 @@ Integration Member ~~~~~~ +.. attributetable:: Member + .. autoclass:: Member() :members: :inherited-members: @@ -2613,36 +2742,48 @@ Member Spotify ~~~~~~~~ +.. attributetable:: Spotify + .. autoclass:: Spotify() :members: VoiceState ~~~~~~~~~~~ +.. attributetable:: VoiceState + .. autoclass:: VoiceState() :members: Emoji ~~~~~ +.. attributetable:: Emoji + .. autoclass:: Emoji() :members: PartialEmoji ~~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: PartialEmoji + .. autoclass:: PartialEmoji() :members: Role ~~~~~ +.. attributetable:: Role + .. autoclass:: Role() :members: TextChannel ~~~~~~~~~~~~ +.. attributetable:: TextChannel + .. autoclass:: TextChannel() :members: :inherited-members: @@ -2657,6 +2798,8 @@ TextChannel VoiceChannel ~~~~~~~~~~~~~ +.. attributetable:: VoiceChannel + .. autoclass:: VoiceChannel() :members: :inherited-members: @@ -2664,6 +2807,8 @@ VoiceChannel CategoryChannel ~~~~~~~~~~~~~~~~~ +.. attributetable:: CategoryChannel + .. autoclass:: CategoryChannel() :members: :inherited-members: @@ -2671,6 +2816,8 @@ CategoryChannel DMChannel ~~~~~~~~~ +.. attributetable:: DMChannel + .. autoclass:: DMChannel() :members: :inherited-members: @@ -2685,6 +2832,8 @@ DMChannel GroupChannel ~~~~~~~~~~~~ +.. attributetable:: GroupChannel + .. autoclass:: GroupChannel() :members: :inherited-members: @@ -2699,18 +2848,24 @@ GroupChannel PartialInviteGuild ~~~~~~~~~~~~~~~~~~~ +.. attributetable:: PartialInviteGuild + .. autoclass:: PartialInviteGuild() :members: PartialInviteChannel ~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: PartialInviteChannel + .. autoclass:: PartialInviteChannel() :members: Invite ~~~~~~~ +.. attributetable:: Invite + .. autoclass:: Invite() :members: @@ -2723,12 +2878,16 @@ Template WidgetChannel ~~~~~~~~~~~~~~~ +.. attributetable:: WidgetChannel + .. autoclass:: WidgetChannel() :members: WidgetMember ~~~~~~~~~~~~~ +.. attributetable:: WidgetMember + .. autoclass:: WidgetMember() :members: :inherited-members: @@ -2736,6 +2895,8 @@ WidgetMember Widget ~~~~~~~ +.. attributetable:: Widget + .. autoclass:: Widget() :members: @@ -2747,36 +2908,48 @@ MessageReference RawMessageDeleteEvent ~~~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: RawMessageDeleteEvent + .. autoclass:: RawMessageDeleteEvent() :members: RawBulkMessageDeleteEvent ~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: RawBulkMessageDeleteEvent + .. autoclass:: RawBulkMessageDeleteEvent() :members: RawMessageUpdateEvent ~~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: RawMessageUpdateEvent + .. autoclass:: RawMessageUpdateEvent() :members: RawReactionActionEvent ~~~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: RawReactionActionEvent + .. autoclass:: RawReactionActionEvent() :members: RawReactionClearEvent ~~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: RawReactionClearEvent + .. autoclass:: RawReactionClearEvent() :members: RawReactionClearEmojiEvent ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: RawReactionClearEmojiEvent + .. autoclass:: RawReactionClearEmojiEvent() :members: @@ -2807,12 +2980,16 @@ Object Embed ~~~~~~ +.. attributetable:: Embed + .. autoclass:: Embed :members: AllowedMentions ~~~~~~~~~~~~~~~~~ +.. attributetable:: AllowedMentions + .. autoclass:: AllowedMentions :members: @@ -2831,54 +3008,72 @@ MemberCacheFlags File ~~~~~ +.. attributetable:: File + .. autoclass:: File :members: Colour ~~~~~~ +.. attributetable:: Colour + .. autoclass:: Colour :members: BaseActivity ~~~~~~~~~~~~~~ +.. attributetable:: BaseActivity + .. autoclass:: BaseActivity :members: Activity ~~~~~~~~~ +.. attributetable:: Activity + .. autoclass:: Activity :members: Game ~~~~~ +.. attributetable:: Game + .. autoclass:: Game :members: Streaming ~~~~~~~~~~~ +.. attributetable:: Streaming + .. autoclass:: Streaming :members: CustomActivity ~~~~~~~~~~~~~~~ +.. attributetable:: CustomActivity + .. autoclass:: CustomActivity :members: Permissions ~~~~~~~~~~~~ +.. attributetable:: Permissions + .. autoclass:: Permissions :members: PermissionOverwrite ~~~~~~~~~~~~~~~~~~~~ +.. attributetable:: PermissionOverwrite + .. autoclass:: PermissionOverwrite :members: diff --git a/docs/conf.py b/docs/conf.py index d87049ac..40edda29 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,7 +38,8 @@ extensions = [ 'sphinx.ext.napoleon', 'sphinxcontrib_trio', 'details', - 'exception_hierarchy' + 'exception_hierarchy', + 'attributetable', ] autodoc_member_order = 'bysource' @@ -143,6 +144,14 @@ html_experimental_html5_writer = True # a list of builtin themes. html_theme = 'basic' +html_context = { + 'discord_invite': 'https://discord.gg/r3sSKJJ', + 'discord_extensions': [ + ('discord.ext.commands', 'ext/commands'), + ('discord.ext.tasks', 'ext/tasks'), + ], +} + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -166,7 +175,7 @@ html_theme = 'basic' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +html_favicon = './images/discord_py_logo.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -233,6 +242,13 @@ html_static_path = ['_static'] # implements a search results scorer. If empty, the default will be used. html_search_scorer = '_static/scorer.js' +html_js_files = [ + 'custom.js', + 'settings.js', + 'copy.js', + 'sidebar.js' +] + # Output file base name for HTML help builder. htmlhelp_basename = 'discord.pydoc' @@ -318,6 +334,6 @@ texinfo_documents = [ #texinfo_no_detailmenu = False def setup(app): - app.add_js_file('custom.js') if app.config.language == 'ja': app.config.intersphinx_mapping['py'] = ('https://docs.python.org/ja/3', None) + app.config.html_context['discord_invite'] = 'https://discord.gg/nXzj3dg' diff --git a/docs/extensions/attributetable.py b/docs/extensions/attributetable.py new file mode 100644 index 00000000..9af83981 --- /dev/null +++ b/docs/extensions/attributetable.py @@ -0,0 +1,241 @@ +from sphinx.util.docutils import SphinxDirective +from sphinx.locale import _ +from docutils import nodes +from sphinx import addnodes + +from collections import OrderedDict, namedtuple +import importlib +import inspect +import os +import re + +class attributetable(nodes.General, nodes.Element): + pass + +class attributetablecolumn(nodes.General, nodes.Element): + pass + +class attributetabletitle(nodes.TextElement): + pass + +class attributetableplaceholder(nodes.General, nodes.Element): + pass + +class attributetablebadge(nodes.TextElement): + pass + +class attributetable_item(nodes.Part, nodes.Element): + pass + +def visit_attributetable_node(self, node): + self.body.append('
' % node['python-class']) + +def visit_attributetablecolumn_node(self, node): + self.body.append(self.starttag(node, 'div', CLASS='py-attribute-table-column')) + +def visit_attributetabletitle_node(self, node): + self.body.append(self.starttag(node, 'span')) + +def visit_attributetablebadge_node(self, node): + attributes = { + 'class': 'py-attribute-table-badge', + 'title': node['badge-type'], + } + self.body.append(self.starttag(node, 'span', **attributes)) + +def visit_attributetable_item_node(self, node): + self.body.append(self.starttag(node, 'li', CLASS='py-attribute-table-entry')) + +def depart_attributetable_node(self, node): + self.body.append('
') + +def depart_attributetablecolumn_node(self, node): + self.body.append('
') + +def depart_attributetabletitle_node(self, node): + self.body.append('') + +def depart_attributetablebadge_node(self, node): + self.body.append('') + +def depart_attributetable_item_node(self, node): + self.body.append('') + +_name_parser_regex = re.compile(r'(?P[\w.]+\.)?(?P\w+)') + +class PyAttributeTable(SphinxDirective): + has_content = False + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def parse_name(self, content): + path, name = _name_parser_regex.match(content).groups() + if path: + modulename = path.rstrip('.') + else: + modulename = self.env.temp_data.get('autodoc:module') + if not modulename: + modulename = self.env.ref_context.get('py:module') + if modulename is None: + raise RuntimeError('modulename somehow None for %s in %s.' % (content, self.env.docname)) + + return modulename, name + + def run(self): + """If you're curious on the HTML this is meant to generate: + +
+
+ _('Attributes') + +
+ +
+ + However, since this requires the tree to be complete + and parsed, it'll need to be done at a different stage and then + replaced. + """ + content = self.arguments[0].strip() + node = attributetableplaceholder('') + modulename, name = self.parse_name(content) + node['python-module'] = modulename + node['python-class'] = name + node['python-full-name'] = '%s.%s' % (modulename, name) + return [node] + +def build_lookup_table(env): + # Given an environment, load up a lookup table of + # full-class-name: objects + result = {} + domain = env.domains['py'] + + ignored = { + 'data', 'exception', 'module', 'class', + } + + for (fullname, _, objtype, docname, _, _) in domain.get_objects(): + if objtype in ignored: + continue + + classname, _, child = fullname.rpartition('.') + try: + result[classname].append(child) + except KeyError: + result[classname] = [child] + + return result + + +TableElement = namedtuple('TableElement', 'fullname label badge') + +def process_attributetable(app, doctree, fromdocname): + env = app.builder.env + + lookup = build_lookup_table(env) + for node in doctree.traverse(attributetableplaceholder): + modulename, classname, fullname = node['python-module'], node['python-class'], node['python-full-name'] + groups = get_class_results(lookup, modulename, classname, fullname) + table = attributetable('') + for label, subitems in groups.items(): + if not subitems: + continue + table.append(class_results_to_node(label, sorted(subitems, key=lambda c: c.label))) + + table['python-class'] = fullname + + if not table: + node.replace_self([]) + else: + node.replace_self([table]) + +def get_class_results(lookup, modulename, name, fullname): + module = importlib.import_module(modulename) + cls = getattr(module, name) + + groups = OrderedDict([ + (_('Attributes'), []), + (_('Methods'), []), + ]) + + try: + members = lookup[fullname] + except KeyError: + return groups + + for attr in members: + attrlookup = '%s.%s' % (fullname, attr) + key = _('Attributes') + badge = None + label = attr + + for base in cls.__mro__: + value = base.__dict__.get(attr) + if value is not None: + break + + if value is not None: + doc = value.__doc__ or '' + if inspect.iscoroutinefunction(value) or doc.startswith('|coro|'): + key = _('Methods') + badge = attributetablebadge('async', 'async') + badge['badge-type'] = _('coroutine') + elif isinstance(value, classmethod): + key = _('Methods') + label = '%s.%s' % (name, attr) + badge = attributetablebadge('cls', 'cls') + badge['badge-type'] = _('classmethod') + elif inspect.isfunction(value): + if doc.startswith(('A decorator', 'A shortcut decorator')): + # finicky but surprisingly consistent + badge = attributetablebadge('@', '@') + badge['badge-type'] = _('decorator') + key = _('Methods') + else: + key = _('Methods') + badge = attributetablebadge('def', 'def') + badge['badge-type'] = _('method') + + groups[key].append(TableElement(fullname=attrlookup, label=label, badge=badge)) + + return groups + +def class_results_to_node(key, elements): + title = attributetabletitle(key, key) + ul = nodes.bullet_list('') + for element in elements: + ref = nodes.reference('', '', internal=True, + refuri='#' + element.fullname, + anchorname='', + *[nodes.Text(element.label)]) + para = addnodes.compact_paragraph('', '', ref) + if element.badge is not None: + ul.append(attributetable_item('', element.badge, para)) + else: + ul.append(attributetable_item('', para)) + + return attributetablecolumn('', title, ul) + +def setup(app): + app.add_directive('attributetable', PyAttributeTable) + app.add_node(attributetable, html=(visit_attributetable_node, depart_attributetable_node)) + app.add_node(attributetablecolumn, html=(visit_attributetablecolumn_node, depart_attributetablecolumn_node)) + app.add_node(attributetabletitle, html=(visit_attributetabletitle_node, depart_attributetabletitle_node)) + app.add_node(attributetablebadge, html=(visit_attributetablebadge_node, depart_attributetablebadge_node)) + app.add_node(attributetable_item, html=(visit_attributetable_item_node, depart_attributetable_item_node)) + app.add_node(attributetableplaceholder) + app.connect('doctree-resolved', process_attributetable) diff --git a/docs/extensions/builder.py b/docs/extensions/builder.py index ec428d8f..792f370e 100644 --- a/docs/extensions/builder.py +++ b/docs/extensions/builder.py @@ -1,5 +1,24 @@ from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.environment.adapters.indexentries import IndexEntries +from sphinx.writers.html5 import HTML5Translator + +class DPYHTML5Translator(HTML5Translator): + def visit_section(self, node): + self.section_level += 1 + self.body.append( + self.starttag(node, 'section')) + + def depart_section(self, node): + self.section_level -= 1 + self.body.append('\n') + + def visit_table(self, node): + self.body.append('
') + super().visit_table(node) + + def depart_table(self, node): + super().depart_table(node) + self.body.append('
') class DPYStandaloneHTMLBuilder(StandaloneHTMLBuilder): # This is mostly copy pasted from Sphinx. @@ -31,16 +50,26 @@ class DPYStandaloneHTMLBuilder(StandaloneHTMLBuilder): else: self.handle_page('genindex', genindexcontext, 'genindex.html') -def get_builder(app): + +def add_custom_jinja2(app): + env = app.builder.templates.environment + env.tests['prefixedwith'] = str.startswith + env.tests['suffixedwith'] = str.endswith + +def add_builders(app): """This is necessary because RTD injects their own for some reason.""" try: original = app.registry.builders['readthedocs'] except KeyError: - return DPYStandaloneHTMLBuilder + app.set_translator('html', DPYHTML5Translator, override=True) + app.add_builder(DPYStandaloneHTMLBuilder, override=True) else: injected_mro = tuple(base if base is not StandaloneHTMLBuilder else DPYStandaloneHTMLBuilder for base in original.mro()[1:]) - return type(original.__name__, injected_mro, {'name': 'readthedocs'}) + new_builder = type(original.__name__, injected_mro, {'name': 'readthedocs'}) + app.set_translator('readthedocs', DPYHTML5Translator, override=True) + app.add_builder(new_builder, override=True) def setup(app): - app.add_builder(get_builder(app), override=True) + add_builders(app) + app.connect('builder-inited', add_custom_jinja2) diff --git a/docs/images/discord_py_logo.ico b/docs/images/discord_py_logo.ico new file mode 100644 index 00000000..209ba4ef Binary files /dev/null and b/docs/images/discord_py_logo.ico differ diff --git a/docs/images/drop_down_icon.svg b/docs/images/drop_down_icon.svg new file mode 100644 index 00000000..e7edbba3 --- /dev/null +++ b/docs/images/drop_down_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/images/snake.png b/docs/images/snake.png deleted file mode 100644 index 62b44617..00000000 Binary files a/docs/images/snake.png and /dev/null differ diff --git a/docs/images/snake.svg b/docs/images/snake.svg new file mode 100644 index 00000000..aa741440 --- /dev/null +++ b/docs/images/snake.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/docs/images/snake_dark.svg b/docs/images/snake_dark.svg new file mode 100644 index 00000000..12022af4 --- /dev/null +++ b/docs/images/snake_dark.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/docs/index.rst b/docs/index.rst index 20c5d183..9a8a37f6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,7 +6,8 @@ Welcome to discord.py =========================== -.. image:: /images/snake.png +.. image:: /images/snake.svg +.. image:: /images/snake_dark.svg discord.py is a modern, easy to use, feature-rich, and async ready API wrapper for Discord. diff --git a/setup.py b/setup.py index ccb9f3d6..27e8908e 100644 --- a/setup.py +++ b/setup.py @@ -36,8 +36,8 @@ with open('README.rst') as f: extras_require = { 'voice': ['PyNaCl==1.3.0'], 'docs': [ - 'sphinx==1.8.5', - 'sphinxcontrib_trio==1.1.1', + 'sphinx==3.0.3', + 'sphinxcontrib_trio==1.1.2', 'sphinxcontrib-websupport', ] }