diff --git a/docs/conf.py b/docs/conf.py index 9a7d581..65dbebd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,6 +9,7 @@ project = "IATI Sphinx Theme" copyright = "2024 IATI Secretariat" author = "IATI Secretariat" +language = "en" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -26,4 +27,11 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "iati_sphinx_theme" +html_theme_options = { + "github_repository": "https://github.com/IATI/sphinx-theme", + "languages": { + "en": "English", + }, +} + todo_include_todos = True diff --git a/docs/index.rst b/docs/index.rst index c5f7da7..2350c4d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,11 +2,6 @@ IATI Sphinx Theme ================= -.. toctree:: - :hidden: - - Home - .. toctree:: :titlesonly: :maxdepth: 1 @@ -35,9 +30,25 @@ Installation Configuration ============= -Plausible Analytics +This theme has multiple options, which can be configured using the :code:`html_theme_options` object in your :code:`conf.py` file. + +.. code-block:: python + + html_theme_options = { + "github_repository": "https://github.com/organisation/repository", + "plausible_domain": "example.com" + } + +There is more information on each option below. + +:code:`github_repository` ------------------- +This should be a link to the Github repository for the documentation site, and is used to link to the source code in the footer of the site. + +:code:`plausible_domain` +------------------------ + To integrate with Plausible Analytics, add the :code:`plausible_domain` option in your project's :code:`conf.py` file. If your docs site is a subdomain for the site it is documenting, use the top level domain for cross-subdomain tracking. diff --git a/iati_sphinx_theme/__init__.py b/iati_sphinx_theme/__init__.py index 1bb9d77..ea3ea5b 100644 --- a/iati_sphinx_theme/__init__.py +++ b/iati_sphinx_theme/__init__.py @@ -9,3 +9,6 @@ def setup(app: sphinx.application.Sphinx) -> None: app.add_html_theme("iati_sphinx_theme", path.abspath(path.dirname(__file__))) app.config["html_permalinks_icon"] = "#" app.config["html_favicon"] = "static/favicon-16x16.png" + app.config["html_context"]["language"] = app.config["language"] + app.add_js_file("header.js") + app.add_js_file("language-switcher.js") diff --git a/iati_sphinx_theme/footer.html b/iati_sphinx_theme/footer.html new file mode 100644 index 0000000..b30f300 --- /dev/null +++ b/iati_sphinx_theme/footer.html @@ -0,0 +1,55 @@ + diff --git a/iati_sphinx_theme/header.html b/iati_sphinx_theme/header.html new file mode 100644 index 0000000..8eaba4e --- /dev/null +++ b/iati_sphinx_theme/header.html @@ -0,0 +1,85 @@ +{% set general_nav_items = [ + {"text": "About IATI", "link": "https://iatistandard.org/en/about/"}, + {"text": "Use Data", "link": "https://iatistandard.org/en/using-data/"}, + {"text": "Publish Data", "link": "https://iatistandard.org/en/guidance/publishing-data/"}, + {"text": "Contact", "link": "https://iatistandard.org/guidance/get-support/"}, +] %} + +
+
+ +
+ +
+ +
+
+ + + + +
+
+ +
+
+ +
+ + {%- include "language-switcher.html" %} + + + Search + + + + +
+ +
+

IATI Tools

+

{{ _(project) }}

+
+ +
+ +
+
+
+ +
diff --git a/iati_sphinx_theme/language-switcher.html b/iati_sphinx_theme/language-switcher.html new file mode 100644 index 0000000..77f3b10 --- /dev/null +++ b/iati_sphinx_theme/language-switcher.html @@ -0,0 +1,10 @@ +
+ + +
diff --git a/iati_sphinx_theme/layout.html b/iati_sphinx_theme/layout.html index 2e1f746..994eacf 100644 --- a/iati_sphinx_theme/layout.html +++ b/iati_sphinx_theme/layout.html @@ -4,29 +4,15 @@ {% if theme_plausible_domain %} {% endif %} + {% endblock %} {%- block header %} -
-
-
- - - -
- -
-
- {{ _(project) }} -
-
+ {%- include "header.html" %} {% endblock %} {%- block relbar1 %}{% endblock %} @@ -49,45 +35,5 @@ {% endblock %} {%- block footer %} - + {%- include "footer.html" %} {%- endblock %} diff --git a/iati_sphinx_theme/static/header.js b/iati_sphinx_theme/static/header.js new file mode 100644 index 0000000..bc165da --- /dev/null +++ b/iati_sphinx_theme/static/header.js @@ -0,0 +1,69 @@ +(function () { + /** + * @param {Object} container DOM element, which will be hidden\displayed (required) + * @param {string} options the class to be toggled. + */ + class IatiMobileNav { + constructor(wrapper, openClass) { + this.wrapper = wrapper; + this.openClass = openClass; + const focusableElements = this.wrapper.querySelectorAll("a, button"); + this.firstElement = focusableElements[0]; + this.lastElement = focusableElements[focusableElements.length - 1]; + } + + show = () => { + this.wrapper.removeAttribute("hidden"); + const reflow = this.wrapper.offsetHeight; + document.addEventListener("keydown", (e) => this.handleKeyDown(e)); + this.wrapper.classList.add(this.openClass); + setTimeout(() => { + this.firstElement.focus(); + }, 500); + }; + + hide = (closeCallBack) => { + this.wrapper.classList.remove(this.openClass); + document.removeEventListener("keydown", (e) => this.handleKeyDown(e)); + setTimeout(() => { + this.wrapper.setAttribute("hidden", "hidden"); + closeCallBack(); + }, 500); + }; + + handleKeyDown(event) { + if (event.key === "Tab") { + if (document.activeElement === this.firstElement && event.shiftKey) { + this.lastElement.focus(); + event.preventDefault(); + } + if (document.activeElement === this.lastElement && !event.shiftKey) { + this.firstElement.focus(); + event.preventDefault(); + } + } + if (event.key == "Escape") { + this.hide(); + } + } + } + + document.addEventListener("DOMContentLoaded", function () { + const iatiMobileNav = new IatiMobileNav( + document.querySelector(".js-iati-mobile-nav"), + "iati-mobile-nav--open" + ); + + const overlay = document.querySelector(".js-iati-mobile-overlay"); + const menuOpenBtn = document.querySelector(".js-iati-menu-toggle-open"); + const menuCloseBtn = document.querySelector(".js-iati-menu-toggle-close"); + const restoreFocus = () => { + menuOpenBtn.focus(); + }; + menuOpenBtn.addEventListener("click", iatiMobileNav.show); + menuCloseBtn.addEventListener("click", () => + iatiMobileNav.hide(restoreFocus) + ); + overlay.addEventListener("click", () => iatiMobileNav.hide(restoreFocus)); + }); +})(); diff --git a/iati_sphinx_theme/static/icon-info.svg b/iati_sphinx_theme/static/icon-info.svg new file mode 100644 index 0000000..02f6aba --- /dev/null +++ b/iati_sphinx_theme/static/icon-info.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/iati_sphinx_theme/static/icon-search.svg b/iati_sphinx_theme/static/icon-search.svg new file mode 100644 index 0000000..d7870d5 --- /dev/null +++ b/iati_sphinx_theme/static/icon-search.svg @@ -0,0 +1,3 @@ + + + diff --git a/iati_sphinx_theme/static/language-switcher.js b/iati_sphinx_theme/static/language-switcher.js new file mode 100644 index 0000000..9bea224 --- /dev/null +++ b/iati_sphinx_theme/static/language-switcher.js @@ -0,0 +1,20 @@ +document.addEventListener("DOMContentLoaded", function () { + const handleChange = (event) => { + const { value } = event.target; + const currentPath = window.location.pathname; + const countryCodeRegex = /^\/[a-z]{2}\//; + const currentPathWithoutCountryCode = currentPath.replace( + countryCodeRegex, + "/" + ); + const newPath = "/" + value + currentPathWithoutCountryCode; + event.target.selectedIndex = Array.from(event.target.options).findIndex( + (option) => option.hasAttribute("selected") + ); + window.location.pathname = newPath; + }; + const languageSwitchers = document.querySelectorAll("#iati-country-switcher"); + languageSwitchers.forEach((languageSwitcher) => { + languageSwitcher.addEventListener("change", handleChange); + }); +}); diff --git a/iati_sphinx_theme/static/logo-colour.svg b/iati_sphinx_theme/static/logo-colour.svg new file mode 100644 index 0000000..b9a8b66 --- /dev/null +++ b/iati_sphinx_theme/static/logo-colour.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iati_sphinx_theme/static/marque-white.svg b/iati_sphinx_theme/static/marque-white.svg new file mode 100644 index 0000000..d84543b --- /dev/null +++ b/iati_sphinx_theme/static/marque-white.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + diff --git a/iati_sphinx_theme/theme.conf b/iati_sphinx_theme/theme.conf index f965bbf..c658db8 100644 --- a/iati_sphinx_theme/theme.conf +++ b/iati_sphinx_theme/theme.conf @@ -4,6 +4,8 @@ stylesheet = iati.css pygments_style = default [options] +github_repository = globaltoc_maxdepth = 2 show_relations = False -plausible_domain = +plausible_domain = +languages = diff --git a/package-lock.json b/package-lock.json index a8f9556..55fcb94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "devDependencies": { "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", - "iati-design-system": "^1.4.0", + "iati-design-system": "^2.0.0", "sass": "^1.75.0", "semantic-release": "^23.1.1", "semantic-release-pypi": "^3.0.2" @@ -2927,9 +2927,9 @@ } }, "node_modules/iati-design-system": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/iati-design-system/-/iati-design-system-1.4.0.tgz", - "integrity": "sha512-AtFJLpfWZAM+hfIoKXbAIrnima4th+oayrnmSE9nt2tunpL1nWA/h3frAOxrrg+nJLGRLsZbigd991SO42EeNQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/iati-design-system/-/iati-design-system-2.0.0.tgz", + "integrity": "sha512-0OJXtrbWyY4iHohb6P6gRoclBIzjPOq0VzscyiZzdTnboYVvryU7KGtH0ys119Sv2dvhAnVCQapiYwWDzU1FMA==", "dev": true, "dependencies": { "normalize-scss": "^8.0.0" diff --git a/package.json b/package.json index 6764d99..6fa0cf9 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "devDependencies": { "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", - "iati-design-system": "^1.4.0", + "iati-design-system": "^2.0.0", "sass": "^1.75.0", "semantic-release": "^23.1.1", "semantic-release-pypi": "^3.0.2" diff --git a/styles/_typography.scss b/styles/_typography.scss index ab7579a..8a03996 100644 --- a/styles/_typography.scss +++ b/styles/_typography.scss @@ -49,6 +49,15 @@ // Code Blocks +code { + @extend .iati-code; +} + +pre { + @extend .iati-code; + @extend .iati-code--block; +} + span.linenos { color: ds.$color-grey-50; margin-right: ds.$padding-block; @@ -71,3 +80,9 @@ span.linenos { dl dt .classifier::before { content: " : "; } + +// Block quotes + +blockquote:not(:has(pre)) { + @extend .iati-quote; +}