diff --git a/docs/source/conf.py b/docs/source/conf.py index 635559dd6..bde2eba26 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -76,17 +76,19 @@ # -- Options for autodoc extension ---------------------------------- # Configure autodoc to show better signatures -autodoc_typehints = 'description' -autodoc_member_order = 'bysource' +autodoc_typehints = "description" +autodoc_member_order = "bysource" add_module_names = False # Don't prepend module names to class/function names # -- Options for breathe extension ---------------------------------- breathe_projects = { - "SampleModule": os.path.join(os.path.dirname(__file__), "examples/doxygen_output/xml") + "SampleModule": os.path.join( + os.path.dirname(__file__), "examples/doxygen_output/xml" + ) } breathe_default_project = "SampleModule" -breathe_default_members = ('members', 'undoc-members') +breathe_default_members = ("members", "undoc-members") # -- Options for myst parser ---------------------------------------- myst_enable_extensions = ["colon_fence"] diff --git a/docs/source/configuration/ai-chatbot.rst b/docs/source/configuration/ai-chatbot.rst index 693832fb3..3a4c34750 100644 --- a/docs/source/configuration/ai-chatbot.rst +++ b/docs/source/configuration/ai-chatbot.rst @@ -7,7 +7,7 @@ ScyllaDB Docs integrates with `Biel.ai `_ to offer a conversat The chatbot can answer documentation-related questions and provide relevant links to help users find the information they need quickly. .. note:: - This feature is in beta and disabled by default. It will be gradually enabled for all documentation sites in a future release. + This feature is in beta and disabled by default. It will be gradually enabled for all documentation sites in a future release. If you want to enable it now, please contact us in Slack (``#scylla-docs`` channel). Installation @@ -24,7 +24,7 @@ To enable the AI chatbot, update your ``conf.py`` file by setting ``hide_ai_chat Usage ----- -Once enabled, the Ask AI button will appear in the documentation interface. +Once enabled, the Ask AI button will appear in the documentation interface. Users can click the button to start a conversation, ask questions, and receive responses with relevant documentation links. .. figure:: images/ai-chatbot.png @@ -61,4 +61,3 @@ If the chatbot does not appear: * Check for errors in the browser console that may indicate issues with the integration. For more details, refer to the `Biel.ai documentation `_. - diff --git a/docs/source/configuration/template.rst b/docs/source/configuration/template.rst index 5a5cd03d3..c2af38109 100644 --- a/docs/source/configuration/template.rst +++ b/docs/source/configuration/template.rst @@ -311,7 +311,7 @@ Configuration options for enabling zendesk. - Description * - ``zendesk_tag`` - string - - + - - Zendesk verification tag. Example: ``gq6ltsh3nfex3cnwfy4aj9``. .. code:: python @@ -334,6 +334,5 @@ Multiversion options - Description * - ``redirect`` - string - - + - - Overrides the default redirection of the main domain when using multiversion. By default, it redirects to ``/stable/``. Overriding setting this can be useful if the main domain page publishes multiple documentation sets. Example: ``/manual/stable/``. - diff --git a/docs/source/deployment/centralized-publication.rst b/docs/source/deployment/centralized-publication.rst index caa6a0eb5..5d22bdf13 100644 --- a/docs/source/deployment/centralized-publication.rst +++ b/docs/source/deployment/centralized-publication.rst @@ -2,8 +2,8 @@ Centralized publication ======================= -Certain core ScyllaDB projects are configured or published from the repository `scylladb/scylladb-docs-homepage `_ -instead of the project repository itself. +Certain core ScyllaDB projects are configured or published from the repository `scylladb/scylladb-docs-homepage `_ +instead of the project repository itself. This allows us to: @@ -44,8 +44,8 @@ To add a new release to the centralized publication, submit a pull request to th { "tags": [], "branches": [ - "master", - "branch-2025.1", + "master", + "branch-2025.1", "branch-2025.2" ], "latest": "branch-2025.1", @@ -63,8 +63,8 @@ To add a new release to the centralized publication, submit a pull request to th { "tags": [], "branches": [ - "master", - "branch-2025.1", + "master", + "branch-2025.1", "branch-2025.2" ], "latest": "branch-2025.2", @@ -98,4 +98,3 @@ You can trigger a manual publication by following these steps: 6. Click the green **Run workflow** button. For more details, see `Manually running a workflow `_. - diff --git a/docs/source/examples/Doxyfile b/docs/source/examples/Doxyfile index eb2e82e4c..cd3059db1 100644 --- a/docs/source/examples/Doxyfile +++ b/docs/source/examples/Doxyfile @@ -25,4 +25,3 @@ EXTRACT_STATIC = YES # Other settings QUIET = YES WARNINGS = NO - diff --git a/docs/source/examples/__init__.py b/docs/source/examples/__init__.py index 176f63654..301baacdd 100644 --- a/docs/source/examples/__init__.py +++ b/docs/source/examples/__init__.py @@ -1,2 +1 @@ """Examples package for ScyllaDB Sphinx Theme documentation.""" - diff --git a/docs/source/examples/_sample_module.h b/docs/source/examples/_sample_module.h index eb24c36aa..a9003c1a9 100644 --- a/docs/source/examples/_sample_module.h +++ b/docs/source/examples/_sample_module.h @@ -26,7 +26,7 @@ class DatabaseConnection { * @param port The database port number (default: 9042) * @param username Optional username for authentication */ - DatabaseConnection(const std::string& host, int port = 9042, + DatabaseConnection(const std::string& host, int port = 9042, const std::string& username = ""); /** @@ -79,4 +79,3 @@ std::string format_query(const std::string& query, int indent = 4); bool validate_connection_params(const std::string& host, int port); #endif // SAMPLE_MODULE_H - diff --git a/docs/source/examples/_sample_module.py b/docs/source/examples/_sample_module.py index 110785044..e0f659a3b 100644 --- a/docs/source/examples/_sample_module.py +++ b/docs/source/examples/_sample_module.py @@ -105,4 +105,3 @@ def validate_connection_params(host, port): MAX_RETRIES = 3 """Maximum number of connection retry attempts""" - diff --git a/docs/source/examples/api-documentation/doxygen.rst b/docs/source/examples/api-documentation/doxygen.rst index 353b1a3ba..ec345308c 100644 --- a/docs/source/examples/api-documentation/doxygen.rst +++ b/docs/source/examples/api-documentation/doxygen.rst @@ -152,7 +152,7 @@ Configure in ``conf.py``: .. code-block:: python extensions = ['breathe', 'exhale'] - + exhale_args = { 'containmentFolder': './api', 'rootFileName': 'library_root.rst', @@ -161,4 +161,3 @@ Configure in ``conf.py``: } Exhale will automatically create a page for each class, function, and file in your project. - diff --git a/docs/source/examples/api-documentation/index.rst b/docs/source/examples/api-documentation/index.rst index 6c6f44d5a..15df87fe4 100644 --- a/docs/source/examples/api-documentation/index.rst +++ b/docs/source/examples/api-documentation/index.rst @@ -20,4 +20,3 @@ This approach keeps your API reference in sync with your codebase. * :doc:`Python ` * :doc:`Doxygen ` * :doc:`REST API (Redocly) ` - diff --git a/docs/source/examples/api-documentation/rest-api.rst b/docs/source/examples/api-documentation/rest-api.rst index 9f139e03c..187414bce 100644 --- a/docs/source/examples/api-documentation/rest-api.rst +++ b/docs/source/examples/api-documentation/rest-api.rst @@ -99,7 +99,7 @@ Create ``_ext/scylladb_openapi.py``: cmd = f"snippet-enricher-cli --targets='shell_curl' --input={output_file}" process = subprocess.Popen(cmd, shell=True, - stdout=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = process.communicate() @@ -251,4 +251,3 @@ Create ``_static/custom.css`` to style Redocly: color: inherit; background: transparent; } - diff --git a/docs/source/examples/code-blocks.rst b/docs/source/examples/code-blocks.rst index d8bd75852..a870021c5 100644 --- a/docs/source/examples/code-blocks.rst +++ b/docs/source/examples/code-blocks.rst @@ -55,7 +55,7 @@ Renders: .. code-block:: rst :linenos: - + Line 1 Line 2 @@ -104,4 +104,4 @@ Renders: Line 1 Line 2 - Line 3 \ No newline at end of file + Line 3 diff --git a/docs/source/examples/diagrams.rst b/docs/source/examples/diagrams.rst index c86fe31ec..55e144b4b 100644 --- a/docs/source/examples/diagrams.rst +++ b/docs/source/examples/diagrams.rst @@ -1,4 +1,4 @@ -Diagrams +Diagrams ======== The documentation toolchain supports rendering diagrams and charts using `Mermaid `_, a library designed for creating sequence diagrams, flowcharts, and other visualizations. @@ -21,4 +21,4 @@ Renders: A --> B B -- Label --> C -For more details, refer to the `sphinxcontrib-mermaid `_ documentation. \ No newline at end of file +For more details, refer to the `sphinxcontrib-mermaid `_ documentation. diff --git a/docs/source/examples/doxygen_output/xml/compound.xsd b/docs/source/examples/doxygen_output/xml/compound.xsd index c8ed42ecd..1c34e0c52 100644 --- a/docs/source/examples/doxygen_output/xml/compound.xsd +++ b/docs/source/examples/doxygen_output/xml/compound.xsd @@ -268,7 +268,7 @@ - + @@ -1222,7 +1222,7 @@ - + @@ -1278,7 +1278,7 @@ - + @@ -1291,14 +1291,14 @@ - + - + @@ -1333,7 +1333,7 @@ - + @@ -1342,7 +1342,7 @@ - + @@ -1696,4 +1696,3 @@ - diff --git a/docs/source/examples/doxygen_output/xml/index.xsd b/docs/source/examples/doxygen_output/xml/index.xsd index 6c847cc36..de4eb6a82 100644 --- a/docs/source/examples/doxygen_output/xml/index.xsd +++ b/docs/source/examples/doxygen_output/xml/index.xsd @@ -28,7 +28,7 @@ - + @@ -69,4 +69,3 @@ - diff --git a/docs/source/examples/grid.rst b/docs/source/examples/grid.rst index 25f42c4b2..1c292267d 100644 --- a/docs/source/examples/grid.rst +++ b/docs/source/examples/grid.rst @@ -1,7 +1,7 @@ Grid ==== -A custom directive that creates responsive grid layouts using Foundation's grid system. +A custom directive that creates responsive grid layouts using Foundation's grid system. Perfect for organizing topic boxes in rows and columns. .. note:: @@ -62,7 +62,7 @@ Supported Content The grid directive works exclusively with **topic-box** directives. Each topic-box within a grid should include Foundation grid classes in its ``:class:`` option to control layout: - ``large-3`` - 4 columns per row on desktop -- ``large-4`` - 3 columns per row on desktop +- ``large-4`` - 3 columns per row on desktop - ``large-6`` - 2 columns per row on desktop - ``large-12`` - 1 column per row (full width) - ``small-6`` - 2 columns per row on mobile @@ -264,4 +264,3 @@ Results in: :class: topic-box--product,large-4,small-6 Documentation for ScyllaDB. - diff --git a/docs/source/examples/mascots.rst b/docs/source/examples/mascots.rst index 30ea9a3a0..8d7fb43c6 100644 --- a/docs/source/examples/mascots.rst +++ b/docs/source/examples/mascots.rst @@ -211,4 +211,3 @@ Available mascot images: - ``/_static/img/mascots-2/stretched-up.svg`` - ``/_static/img/mascots-2/toolbox.svg`` - ``/_static/img/mascots-2/university.svg`` - diff --git a/docs/source/examples/topic-box.rst b/docs/source/examples/topic-box.rst index 9f2402798..79773dd52 100644 --- a/docs/source/examples/topic-box.rst +++ b/docs/source/examples/topic-box.rst @@ -1,7 +1,7 @@ Topic box ========= -A custom directive that creates graphical boxes (cards) for navigation and content organization. +A custom directive that creates graphical boxes (cards) for navigation and content organization. Syntax ------ @@ -269,4 +269,3 @@ Results in: :class: topic-box--product Lorem ipsum dolor sit amet, consectetur adipiscing elit. - diff --git a/docs/source/examples/videos.rst b/docs/source/examples/videos.rst index 5df78a064..b85fdc2d8 100644 --- a/docs/source/examples/videos.rst +++ b/docs/source/examples/videos.rst @@ -12,9 +12,9 @@ To embed a video using an iframe, use the ``raw`` directive with HTML content. .. raw:: html - @@ -22,9 +22,9 @@ Renders as: .. raw:: html - @@ -38,11 +38,11 @@ To make the iframe responsive and take the full width of the container while mai .. raw:: html
- @@ -53,11 +53,11 @@ Renders as: .. raw:: html
- @@ -70,4 +70,3 @@ Tips * **Aspect ratio**: Adjust ``padding-bottom`` to change the aspect ratio. For 16:9 use 56.25%, for 4:3 use 75%. * **Start time**: Add ``?start=60`` to start the video at a specific time (60 seconds in this example). - diff --git a/docs/source/upgrade/1-5-to-1-6.rst b/docs/source/upgrade/1-5-to-1-6.rst index 95fd9d2b0..9355e5653 100644 --- a/docs/source/upgrade/1-5-to-1-6.rst +++ b/docs/source/upgrade/1-5-to-1-6.rst @@ -48,4 +48,4 @@ Here are the main breaking changes between the 1.5 and 1.6 versions. cd docs make preview -#. Review and address any warnings that may arise in the terminal during the build process. \ No newline at end of file +#. Review and address any warnings that may arise in the terminal during the build process. diff --git a/docs/source/upgrade/CHANGELOG.md b/docs/source/upgrade/CHANGELOG.md index 38e5e4713..d5a365d4e 100644 --- a/docs/source/upgrade/CHANGELOG.md +++ b/docs/source/upgrade/CHANGELOG.md @@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.8.9 - 21 November 2025 + +### Added + +- [#1516](https://github.com/scylladb/sphinx-scylladb-theme/pull/1516): Added styling for API reference documentation, including Python autodoc, Doxygen/Breathe, and REST API documentation. +- [#1516](https://github.com/scylladb/sphinx-scylladb-theme/pull/1516): Added support for three navigation levels in the right sidebar with options to control depth per page and project. +- [#1507](https://github.com/scylladb/sphinx-scylladb-theme/pull/1507): Added documentation example for embedding videos in documentation pages. + +### Updated + +- [#1513](https://github.com/scylladb/sphinx-scylladb-theme/issues/1513): Updated driver links in the header navigation. + +### Fixed + +- [#1498](https://github.com/scylladb/sphinx-scylladb-theme/pull/1498): Fixed announcement banner display issues on mobile devices. + ## 1.8.8 - 2 September 2025 ### Added diff --git a/docs/source/upgrade/_partials/docs-pages-1.7.yml b/docs/source/upgrade/_partials/docs-pages-1.7.yml index bd1355f26..4d7ba4c06 100644 --- a/docs/source/upgrade/_partials/docs-pages-1.7.yml +++ b/docs/source/upgrade/_partials/docs-pages-1.7.yml @@ -23,4 +23,3 @@ jobs: with: python-version: '3.10' # (...) - diff --git a/extensions/sphinx-multiversion/sphinx_multiversion/main.py b/extensions/sphinx-multiversion/sphinx_multiversion/main.py index c9ace2aff..a7d26c4b8 100644 --- a/extensions/sphinx-multiversion/sphinx_multiversion/main.py +++ b/extensions/sphinx-multiversion/sphinx_multiversion/main.py @@ -308,9 +308,9 @@ def main(argv=None): current_sourcedir = os.path.join(repopath, sourcedir) project = sphinx_project.Project(current_sourcedir, source_suffixes) - - myst_substitutions = getattr(current_config, 'myst_substitutions', {}) - + + myst_substitutions = getattr(current_config, "myst_substitutions", {}) + metadata[gitref.name] = { "name": gitref.name, "version": current_config.version, diff --git a/pyproject.toml b/pyproject.toml index 147ce3481..e4c60cc1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "sphinx-scylladb-theme" -version = "1.8.8" +version = "1.8.9" description = "A Sphinx Theme for ScyllaDB documentation projects" authors = ["David García "] exclude = [".github", "config", "docs", "extensions", ".postcss.config.js", ".prettierrc.json", "deploy.sh", "src", "package.json", "package-lock.json"] diff --git a/sphinx_scylladb_theme/__init__.py b/sphinx_scylladb_theme/__init__.py index 203472d29..9e3c7540a 100644 --- a/sphinx_scylladb_theme/__init__.py +++ b/sphinx_scylladb_theme/__init__.py @@ -3,15 +3,15 @@ import sphinx_collapse import sphinx_copybutton import sphinx_substitution_extensions -from sphinxcontrib import mermaid from notfound import extension as not_found from sphinx_tabs import tabs +from sphinxcontrib import mermaid from sphinx_scylladb_theme._version import version from sphinx_scylladb_theme.extensions import ( alerts, - hero_box, grid, + hero_box, include_tooltip, labels, multiversion, @@ -60,7 +60,9 @@ def update_context(app, pagename, templatename, context, doctree): context["landing"] = "landing" in file_meta # TOC depth configuration (min: 2, max: 4) - default_toc_depth = getattr(app.config, "html_theme_options", {}).get("secondary_sidebar_toc_depth", 2) + default_toc_depth = getattr(app.config, "html_theme_options", {}).get( + "secondary_sidebar_toc_depth", 2 + ) page_toc_depth = file_meta.get("toc-depth", default_toc_depth) # Clamp between 2 and 4 context["toc_depth"] = max(2, min(4, int(page_toc_depth))) diff --git a/sphinx_scylladb_theme/extensions/alerts.py b/sphinx_scylladb_theme/extensions/alerts.py index d74455e9c..7c4aabe91 100644 --- a/sphinx_scylladb_theme/extensions/alerts.py +++ b/sphinx_scylladb_theme/extensions/alerts.py @@ -31,7 +31,7 @@ def run(self): if target == "_blank": target_attr = 'target="_blank"' else: - target_attr = '' + target_attr = "" html0 = generate_template( """ @@ -49,7 +49,7 @@ def run(self): ) alert_node = nodes.raw(text=html0, format="html") - + return [alert_node] diff --git a/sphinx_scylladb_theme/extensions/grid.py b/sphinx_scylladb_theme/extensions/grid.py index 600ebc26a..216ab11c1 100644 --- a/sphinx_scylladb_theme/extensions/grid.py +++ b/sphinx_scylladb_theme/extensions/grid.py @@ -24,12 +24,14 @@ def run(self): # Add type modifier grid_type = self.options.get("type", "default") if grid_type in ["scrollable", "products"]: - container_class_name = f"{container_class_name} topics-grid--{grid_type}".strip() + container_class_name = ( + f"{container_class_name} topics-grid--{grid_type}".strip() + ) # Generate title and text if provided title = self.options.get("title", "") text = self.options.get("text", "") - + header = "" if title or text: header = generate_template( @@ -74,4 +76,4 @@ def setup(app): "version": "0.1", "parallel_read_safe": True, "parallel_write_safe": True, - } \ No newline at end of file + } diff --git a/sphinx_scylladb_theme/extensions/hero_box.py b/sphinx_scylladb_theme/extensions/hero_box.py index a5db78b98..78eaeab32 100644 --- a/sphinx_scylladb_theme/extensions/hero_box.py +++ b/sphinx_scylladb_theme/extensions/hero_box.py @@ -13,7 +13,7 @@ class HeroBox(Directive): option_spec = { "title": directives.unchanged_required, "class": directives.path, - "text": directives.unchanged_required, # unused, left for compatibility + "text": directives.unchanged_required, # unused, left for compatibility "cta": directives.unchanged_required, "image": directives.path, "button_style": directives.path, @@ -30,8 +30,12 @@ class HeroBox(Directive): def run(self): class_name = "hero" container_class_name = self.options.get("class", "") - - content_page_style = ' style="margin-top: 2em; margin-bottom: 2em;"' if "content_page" in self.options else "" + + content_page_style = ( + ' style="margin-top: 2em; margin-bottom: 2em;"' + if "content_page" in self.options + else "" + ) image = self.options.get("image") image = ( @@ -89,9 +93,9 @@ def run(self): ) has_search_box = "search_box" in self.options - + ai_chatbot_id = self.options.get("ai_chatbot_id") - + ask_ai_section = "" if ai_chatbot_id: ask_ai_section = """ diff --git a/sphinx_scylladb_theme/extensions/include_tooltip.py b/sphinx_scylladb_theme/extensions/include_tooltip.py index e694a4b1c..200e6554b 100644 --- a/sphinx_scylladb_theme/extensions/include_tooltip.py +++ b/sphinx_scylladb_theme/extensions/include_tooltip.py @@ -5,34 +5,38 @@ from docutils import nodes from docutils.parsers.rst import roles -from sphinx.util import logging from sphinx.transforms.post_transforms import SphinxPostTransform +from sphinx.util import logging LOGGER = logging.getLogger(__name__) + class include_tooltip_node(nodes.inline, nodes.Element): pass + def visit_include_tooltip_node_html(self, node): - tooltip_text = node.get('tooltip', '') + tooltip_text = node.get("tooltip", "") self.body.append( f'' ) + def depart_include_tooltip_node_html(self, node): - self.body.append('') + self.body.append("") + class TooltipPostTransform(SphinxPostTransform): - default_priority = 500 + default_priority = 500 def apply(self, **kwargs): env = self.env - std_domain = env.get_domain('std') + std_domain = env.get_domain("std") glossary_terms = std_domain._terms for node in self.document.traverse(include_tooltip_node): - tooltip_source = node.get('tooltip_source', '').lower() - tooltip_text = node.get('tooltip_source', '') + tooltip_source = node.get("tooltip_source", "").lower() + tooltip_text = node.get("tooltip_source", "") if tooltip_source in glossary_terms: docname, labelid = glossary_terms[tooltip_source] @@ -46,36 +50,42 @@ def apply(self, **kwargs): tooltip_text = sibling.astext() break except Exception as e: - LOGGER.error(f"Error retrieving tooltip from glossary during post-transform: {e}") - - node['tooltip'] = tooltip_text + LOGGER.error( + f"Error retrieving tooltip from glossary during post-transform: {e}" + ) + + node["tooltip"] = tooltip_text + def include_tooltip_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - if '<' in text and '>' in text: - start_index = text.index('<') - end_index = text.rindex('>') + if "<" in text and ">" in text: + start_index = text.index("<") + end_index = text.rindex(">") main_text = text[:start_index].strip() - tooltip_source = text[start_index + 1:end_index].strip() + tooltip_source = text[start_index + 1 : end_index].strip() else: msg = inliner.reporter.error( "Invalid syntax for include_tooltip role. Expected format: 'display text '", - line=lineno + line=lineno, ) return [inliner.problematic(rawtext, rawtext, msg)], [msg] node = include_tooltip_node(main_text, main_text) - node['tooltip_source'] = tooltip_source + node["tooltip_source"] = tooltip_source return [node], [] + def setup(app): - roles.register_local_role('include_tooltip', include_tooltip_role) - app.add_node(include_tooltip_node, html=(visit_include_tooltip_node_html, depart_include_tooltip_node_html)) + roles.register_local_role("include_tooltip", include_tooltip_role) + app.add_node( + include_tooltip_node, + html=(visit_include_tooltip_node_html, depart_include_tooltip_node_html), + ) app.add_post_transform(TooltipPostTransform) - + return { - 'version': '1.0', - 'parallel_read_safe': True, - 'parallel_write_safe': True, + "version": "1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, } - diff --git a/sphinx_scylladb_theme/extensions/multiversion.py b/sphinx_scylladb_theme/extensions/multiversion.py index 389aec355..4427ff0cb 100644 --- a/sphinx_scylladb_theme/extensions/multiversion.py +++ b/sphinx_scylladb_theme/extensions/multiversion.py @@ -80,12 +80,12 @@ def create_redirect_to_latest_version(app, exception): and app.config.smv_rename_latest_version ): latest_dir = app.config.smv_rename_latest_version - + theme_options = app.config.html_theme_options custom_redirect = theme_options.get("redirect", "") if custom_redirect: latest_dir = custom_redirect - + out_dir = Path(app.builder.outdir) head = out_dir.parent zendesk_tag = theme_options.get("zendesk_tag", "") diff --git a/sphinx_scylladb_theme/extensions/navigation.py b/sphinx_scylladb_theme/extensions/navigation.py index 06bd83a02..db43c2ed3 100644 --- a/sphinx_scylladb_theme/extensions/navigation.py +++ b/sphinx_scylladb_theme/extensions/navigation.py @@ -45,9 +45,7 @@ def get_navigation_tree(toctree_html: str, collapse: bool) -> str: # Add the "label" for the checkbox which will get filled. label = soup.new_tag("label", attrs={"for": checkbox_name}) - label.append( - soup.new_tag("i", attrs={"class": "icon-chevron-right"}) - ) + label.append(soup.new_tag("i", attrs={"class": "icon-chevron-right"})) element.insert(1, label) space = soup.new_tag("div", attrs={"class": "break"}) element.insert(2, space) diff --git a/sphinx_scylladb_theme/extensions/topic_box.py b/sphinx_scylladb_theme/extensions/topic_box.py index 63886c232..9eda7fc5c 100644 --- a/sphinx_scylladb_theme/extensions/topic_box.py +++ b/sphinx_scylladb_theme/extensions/topic_box.py @@ -4,7 +4,6 @@ from docutils import nodes from docutils.parsers.rst import Directive, directives -import os from .utils import generate_template, is_url, resolve_link @@ -17,7 +16,7 @@ class TopicBox(Directive): "link_target": directives.path, "anchor": directives.path, "icon": directives.path, - "icon_color": directives.path, # unused, left for compatibility + "icon_color": directives.path, # unused, left for compatibility "image": directives.path, "class": directives.unchanged, } @@ -29,7 +28,7 @@ def run(self): link = self.options.get("link") link_target = self.options.get("link_target", "auto") target_attr = "" - + if link: env = self.state.document.settings.env link = resolve_link(link, env) diff --git a/sphinx_scylladb_theme/extensions/utils.py b/sphinx_scylladb_theme/extensions/utils.py index d782eeedb..23bd88062 100644 --- a/sphinx_scylladb_theme/extensions/utils.py +++ b/sphinx_scylladb_theme/extensions/utils.py @@ -87,43 +87,45 @@ def is_url(path): def resolve_link(link, env): """ Resolves internal Sphinx links to proper URLs. - + :param link: The link to resolve (absolute or relative path). :type link: str - + :param env: The Sphinx environment object. :type env: sphinx.environment.BuildEnvironment - + :return: The resolved link URL. :rtype: str """ if not link or is_url(link): return link - + # Handle anchor links - if link.startswith('#'): + if link.startswith("#"): return link - - if link.startswith('/'): + + if link.startswith("/"): # Absolute path: resolve from project root target_docname = link[1:] # Remove leading slash else: # Relative path: resolve from current document's directory current_dir = os.path.dirname(env.docname) if current_dir: - target_docname = os.path.normpath(os.path.join(current_dir, link)).replace(os.sep, '/') + target_docname = os.path.normpath(os.path.join(current_dir, link)).replace( + os.sep, "/" + ) else: target_docname = link - + # Remove .html extension if present - if target_docname.endswith('.html'): + if target_docname.endswith(".html"): target_docname = target_docname[:-5] - + # Try to resolve the link if target_docname in env.found_docs: return env.app.builder.get_relative_uri(env.docname, target_docname) - elif target_docname + '/index' in env.found_docs: - return env.app.builder.get_relative_uri(env.docname, target_docname + '/index') + elif target_docname + "/index" in env.found_docs: + return env.app.builder.get_relative_uri(env.docname, target_docname + "/index") else: # Fallback: add .html extension - return target_docname + '.html' + return target_docname + ".html" diff --git a/sphinx_scylladb_theme/footer.html b/sphinx_scylladb_theme/footer.html index 9ef384963..55db2724c 100644 --- a/sphinx_scylladb_theme/footer.html +++ b/sphinx_scylladb_theme/footer.html @@ -7,7 +7,7 @@ Tutorials University Contact Us + target="_blank">Contact Us About Us
{% if show_copyright %} - - {% endif %} + + {% endif %}
{% if theme_hide_ai_chatbot|lower != 'true' %} - + Ask AI {% endif %} diff --git a/sphinx_scylladb_theme/header.html b/sphinx_scylladb_theme/header.html index 960dbc0ea..9915f7504 100644 --- a/sphinx_scylladb_theme/header.html +++ b/sphinx_scylladb_theme/header.html @@ -55,11 +55,11 @@ DynamoDB Drivers -
  • - - Supported Driver Versions - -
  • +
  • + + Supported Driver Versions + +
  • @@ -98,11 +98,11 @@ {% if theme_hide_ai_chatbot|lower != 'true' %} - + Ask AI {% endif %} diff --git a/sphinx_scylladb_theme/layout.html b/sphinx_scylladb_theme/layout.html index 140d957d8..1fb2f61a9 100644 --- a/sphinx_scylladb_theme/layout.html +++ b/sphinx_scylladb_theme/layout.html @@ -31,10 +31,10 @@ {% if theme_hide_ai_chatbot|lower != 'true' %} - - + + {% endif %} - + {% for css in css_files %} {% if css|attr("filename") %} {{ css_tag(css) }} @@ -103,30 +103,30 @@ {% endif %} {% if not hide_secondary_sidebar %} - - + {% include 'footer.html' %} diff --git a/sphinx_scylladb_theme/side-nav-toggle.html b/sphinx_scylladb_theme/side-nav-toggle.html index cf0d44bca..7a86b3b18 100644 --- a/sphinx_scylladb_theme/side-nav-toggle.html +++ b/sphinx_scylladb_theme/side-nav-toggle.html @@ -3,4 +3,4 @@
    - \ No newline at end of file + diff --git a/sphinx_scylladb_theme/side-nav.html b/sphinx_scylladb_theme/side-nav.html index 2679f70da..874dd59f6 100644 --- a/sphinx_scylladb_theme/side-nav.html +++ b/sphinx_scylladb_theme/side-nav.html @@ -19,4 +19,4 @@ collapse=theme_collapse_navigation|tobool)}} - \ No newline at end of file + diff --git a/sphinx_scylladb_theme/utils.py b/sphinx_scylladb_theme/utils.py index 264f95d90..c96828e54 100644 --- a/sphinx_scylladb_theme/utils.py +++ b/sphinx_scylladb_theme/utils.py @@ -1,5 +1,5 @@ import requests -import json + def multiversion_regex_builder(versions): """Generates a regex string from a list of versions. diff --git a/tests/extensions/test_alerts.py b/tests/extensions/test_alerts.py index 2eef2805f..d4d915d22 100644 --- a/tests/extensions/test_alerts.py +++ b/tests/extensions/test_alerts.py @@ -1,4 +1,5 @@ from unittest.mock import Mock + import pytest from bs4 import BeautifulSoup as bs @@ -7,7 +8,12 @@ test_data = [ [ [], - {"link": "https://scylladb.com", "link_text": "Learn more", "icon": "logs", "target": "_blank"}, + { + "link": "https://scylladb.com", + "link_text": "Learn more", + "icon": "logs", + "target": "_blank", + }, ["We’re updating our license & versioning policy."], """
    @@ -18,7 +24,11 @@ ], [ [], - {"link": "https://scylladb.com", "link_text": "Learn more about the change", "icon": "logs"}, + { + "link": "https://scylladb.com", + "link_text": "Learn more about the change", + "icon": "logs", + }, ["We’re updating our license & versioning policy."], """
    diff --git a/tests/extensions/test_grid.py b/tests/extensions/test_grid.py index 548c6fe96..0145574fd 100644 --- a/tests/extensions/test_grid.py +++ b/tests/extensions/test_grid.py @@ -108,4 +108,4 @@ def test(arguments, options, content, expected): assert ( bs(result[0].astext(), "html.parser").prettify() == bs(expected, "html.parser").prettify() - ) \ No newline at end of file + ) diff --git a/tests/extensions/test_hero_box.py b/tests/extensions/test_hero_box.py index 2d6140706..a3664f9fb 100644 --- a/tests/extensions/test_hero_box.py +++ b/tests/extensions/test_hero_box.py @@ -58,7 +58,11 @@ [ # Test search box with AI chatbot [], - {"title": "Lorem Ipsum", "search_box": True, "ai_chatbot_id": "test-chatbot-id"}, + { + "title": "Lorem Ipsum", + "search_box": True, + "ai_chatbot_id": "test-chatbot-id", + }, ["Content"], """
    @@ -135,7 +139,7 @@
    diff --git a/tests/extensions/test_include_tooltip.py b/tests/extensions/test_include_tooltip.py index 6b5676fb1..dccf3c40e 100644 --- a/tests/extensions/test_include_tooltip.py +++ b/tests/extensions/test_include_tooltip.py @@ -1,10 +1,11 @@ from unittest.mock import Mock + import pytest from bs4 import BeautifulSoup as bs -from docutils import nodes + from sphinx_scylladb_theme.extensions.include_tooltip import ( - include_tooltip_role, include_tooltip_node, + include_tooltip_role, ) tooltip_data = [ @@ -22,11 +23,18 @@ mock_inliner.document.settings.env = Mock() mock_inliner.document.reporter.error = Mock() -@pytest.mark.parametrize("role_name, input_text, expected_output, glossary, is_error", tooltip_data) -def test_include_tooltip_role(role_name, input_text, expected_output, glossary, is_error): + +@pytest.mark.parametrize( + "role_name, input_text, expected_output, glossary, is_error", tooltip_data +) +def test_include_tooltip_role( + role_name, input_text, expected_output, glossary, is_error +): glossary = glossary or {} - mock_inliner.document.settings.env.get_domain = Mock(return_value=Mock(_terms=glossary)) - + mock_inliner.document.settings.env.get_domain = Mock( + return_value=Mock(_terms=glossary) + ) + name = role_name rawtext = input_text text = input_text @@ -35,11 +43,16 @@ def test_include_tooltip_role(role_name, input_text, expected_output, glossary, options = {} content = [] - result, messages = include_tooltip_role(name, rawtext, text, lineno, inliner, options, content) - + result, messages = include_tooltip_role( + name, rawtext, text, lineno, inliner, options, content + ) + assert len(result) == 1 node = result[0] assert isinstance(node, include_tooltip_node) output_html = f'{node.astext()}' - assert bs(output_html, "html.parser").prettify() == bs(expected_output, "html.parser").prettify() + assert ( + bs(output_html, "html.parser").prettify() + == bs(expected_output, "html.parser").prettify() + ) diff --git a/tests/test_utils.py b/tests/test_utils.py index 3c7ee86e2..f8f107355 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,12 @@ +from unittest.mock import MagicMock, patch + import requests -from sphinx_scylladb_theme.utils import multiversion_regex_builder, fetch_multiversion_configuration + from sphinx_scylladb_theme.extensions.utils import resolve_link -from unittest.mock import patch, MagicMock +from sphinx_scylladb_theme.utils import ( + fetch_multiversion_configuration, + multiversion_regex_builder, +) def test_multiversion_regex_builder_empty(): @@ -23,6 +28,7 @@ def test_multiversion_regex_builder_many_version(): versions = ["1.0", "2.0"] assert multiversion_regex_builder(versions) == r"\b(^1.0$|^2.0$)\b" + def test_fetch_multiversion_configuration_success(): url = "https://example.com/success" @@ -83,7 +89,7 @@ def test_resolve_link_empty(): env = MagicMock() result = resolve_link("", env) assert result == "" - + result = resolve_link(None, env) assert result is None @@ -94,10 +100,12 @@ def test_resolve_link_absolute_path(): env.docname = "examples/topic-box" env.found_docs = {"getting-started/installation"} env.app.builder.get_relative_uri.return_value = "getting-started/installation.html" - + result = resolve_link("/getting-started/installation", env) assert result == "getting-started/installation.html" - env.app.builder.get_relative_uri.assert_called_with("examples/topic-box", "getting-started/installation") + env.app.builder.get_relative_uri.assert_called_with( + "examples/topic-box", "getting-started/installation" + ) def test_resolve_link_relative_path(): @@ -106,10 +114,12 @@ def test_resolve_link_relative_path(): env.docname = "examples/topic-box" env.found_docs = {"examples/code-blocks"} env.app.builder.get_relative_uri.return_value = "code-blocks.html" - + result = resolve_link("code-blocks", env) assert result == "code-blocks.html" - env.app.builder.get_relative_uri.assert_called_with("examples/topic-box", "examples/code-blocks") + env.app.builder.get_relative_uri.assert_called_with( + "examples/topic-box", "examples/code-blocks" + ) def test_resolve_link_parent_directory(): @@ -118,10 +128,12 @@ def test_resolve_link_parent_directory(): env.docname = "examples/topic-box" env.found_docs = {"getting-started/installation"} env.app.builder.get_relative_uri.return_value = "getting-started/installation.html" - + result = resolve_link("../getting-started/installation", env) assert result == "getting-started/installation.html" - env.app.builder.get_relative_uri.assert_called_with("examples/topic-box", "getting-started/installation") + env.app.builder.get_relative_uri.assert_called_with( + "examples/topic-box", "getting-started/installation" + ) def test_resolve_link_index_fallback(): @@ -130,10 +142,12 @@ def test_resolve_link_index_fallback(): env.docname = "examples/topic-box" env.found_docs = {"getting-started/index"} env.app.builder.get_relative_uri.return_value = "getting-started/index.html" - + result = resolve_link("/getting-started", env) assert result == "getting-started/index.html" - env.app.builder.get_relative_uri.assert_called_with("examples/topic-box", "getting-started/index") + env.app.builder.get_relative_uri.assert_called_with( + "examples/topic-box", "getting-started/index" + ) def test_resolve_link_html_fallback(): @@ -141,7 +155,7 @@ def test_resolve_link_html_fallback(): env = MagicMock() env.docname = "examples/topic-box" env.found_docs = set() # Empty set, no documents found - + result = resolve_link("/nonexistent", env) assert result == "nonexistent.html" @@ -151,6 +165,6 @@ def test_resolve_link_anchor(): env = MagicMock() result = resolve_link("#section-name", env) assert result == "#section-name" - + result = resolve_link("#", env) assert result == "#"