Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ CHANGES

Unreleased
----------
- Use Furo's navigation component through ``sphinx-design-elements``'
``linktree``. Thanks, @pradyunsg.

2025/11/05 0.42.0
-----------------
Expand Down
12 changes: 12 additions & 0 deletions docs/myst/linktree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Link Tree


## About

The link tree is a programmable toc tree.


## Example

```{linktree}
```
17 changes: 17 additions & 0 deletions docs/rst/linktree.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#########
Link Tree
#########


*****
About
*****

The link tree is a programmable toc tree.


*******
Example
*******

.. linktree::
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"sphinx>=7.1,<9",
"sphinx-basic-ng==1.0.0b2",
"sphinx-copybutton>=0.3.1,<1",
"sphinx-design-elements==0.4.0",
"sphinx-design-elements @ git+https://github.com/tech-writing/sphinx-design-elements@linktree",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to assemble this yesterday to see what's missing....

Copy link
Member Author

@amotl amotl Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and encountered an "unexpected" exception on CI:

ImportError: cannot import name 'TocTree' from 'sphinx.environment'

-- https://github.com/crate/crate-docs-theme/actions/runs/20082409491/job/57612387226?pr=405#step:7:492

Copy link
Member Author

@amotl amotl Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this doesn't mean much, because it's all just a draft, originally conceived more than two years ago. However, it highlights that software parts currently do NOT fit together well, so the package needs some more love. A little import error per se is nothing to worry about, I am sure there might be the one or the other different obstacle along the way to general availability.

Copy link
Contributor

@bmunkholm bmunkholm Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested a fix for the build issue. But yeah, looking at the code and the amount of remaining todos, it seems there still is quite a bit of work left? While this is likely a better way, it's probably a bit too involved for me at this moment.

"sphinx-inline-tabs",
"sphinx-sitemap<2.10.0",
"sphinx-togglebutton<1",
Expand Down
Empty file added src/crate/theme/ext/__init__.py
Empty file.
59 changes: 59 additions & 0 deletions src/crate/theme/ext/navigation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# -*- coding: utf-8; -*-
#
# Licensed to Crate (https://crate.io) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. Crate licenses
# this file to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may
# obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# However, if you have executed another commercial license agreement
# with Crate these terms will supersede the license and you may use the
# software solely pursuant to the terms of the relevant commercial agreement.

import logging
import typing as t

from sphinx.application import Sphinx

from crate.theme.ext.sidebar import make_primary_tree
from crate.theme.rtd import __version__
from sphinx.builders.html import StandaloneHTMLBuilder

logger = logging.getLogger(__name__)


def html_page_context(
app: Sphinx,
pagename: str,
templatename: str,
context: t.Dict[str, t.Any],
doctree: t.Any,
) -> None:
"""
Sphinx HTML page context provider.
"""
if not isinstance(app.builder, StandaloneHTMLBuilder):
raise Exception(
"Theme is being used with a non-HTML builder. "
"If you're seeing this error, it is a symptom of a mistake in your "
"configuration."
)

# Basic constants
context["theme_version"] = __version__

# Navigation tree component from `sphinx-design-elements`.
try:
primary_tree = make_primary_tree(builder=app.builder, context=context)
context["ng_navigation_tree"] = primary_tree.render()
except Exception as ex:
logger.exception("Unable to compute primary navigation tree")
118 changes: 118 additions & 0 deletions src/crate/theme/ext/sidebar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# -*- coding: utf-8; -*-
#
# Licensed to Crate (https://crate.io) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. Crate licenses
# this file to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may
# obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# However, if you have executed another commercial license agreement
# with Crate these terms will supersede the license and you may use the
# software solely pursuant to the terms of the relevant commercial agreement.

import typing as t

from sphinx.builders.html import StandaloneHTMLBuilder

from sphinx_design_elements.lib.linktree import LinkTree


def make_primary_tree(builder: StandaloneHTMLBuilder, context: t.Dict[str, t.Any]) -> LinkTree:
"""
A navigation tree demo defined with Python code.

It includes two sections:

- The vanilla toctree of the project at hand..
- A linktree composed of Sphinx references or URLs.
"""
project_name = context["project"]

# Create LinkTree component.
linktree = LinkTree.from_context(builder=builder, context=context)
linktree.remove_from_title("CrateDB")
doc = linktree.api.doc
ref = linktree.api.ref
link = linktree.api.link

# Add section about project (self).
project = \
linktree \
.project(docname=project_name, title=project_name)

# .title("Customized TocTree") \

# 1. On specific projects, add the vanilla toctree.
# Here, also customize it for demonstration purposes.
if project_name == "CrateDB documentation theme":

# Add vanilla project toctree.
project.toctree()

# Add custom navigation items.
# TODO: Find a way to pull additional navigation hints from project
# markup itself, in order to get rid of this anomaly.
project.add(
doc(name="admonitions", label="Admonitions"),
doc(name="codesnippets", label="Code snippets"),
doc(name="myst/mermaid", label="Mermaid diagrams, written in Markdown"),
)

# 2. Add section with links to intersphinx targets.

# CrateDB Database.
linktree \
.title("CrateDB Database") \
.add(
ref(target="guide:getting-started", label="Getting started"),
ref(target="guide:index", label="CrateDB Handbook"),
ref(target="crate-reference:index", label="CrateDB Reference"),
ref(target="ctk:index", label="CrateDB Toolkit"),
)

# CrateDB Cloud.
linktree \
.title("CrateDB Cloud") \
.add(
ref("cloud:index"),
ref("cloud-cli:index"),
)

# CrateDB clients.
linktree \
.title("Clients") \
.add(
ref("crate-admin-ui:index"),
ref("crate-crash:index"),
ref("guide:connect"),
ref("connect-java"),
ref("crate-npgsql:index"),
ref("crate-dbal:index"),
ref("crate-pdo:index"),
ref("crate-python:index"),
)

# Other links.
linktree \
.title("Miscellaneous") \
.add(
link(uri="https://crate.io/support/", label="Support"),
link(uri="https://community.crate.io/", label="Community"),
link(uri="https://community.crate.io/t/overview-of-cratedb-integration-tutorials/1015", label="Integration tutorials"),
link(uri="https://github.com/crate/cratedb-examples", label="Integration examples"),
link(uri="https://github.com/crate/crate-sample-apps", label="Sample applications"),
ref("sql-99:index"),
# ref("crate-docs-theme:index"),
# ref("crate-docs:index"),
)

return linktree
8 changes: 5 additions & 3 deletions src/crate/theme/rtd/conf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
import os

from crate.theme import rtd as theme
from crate.theme.ext import navigation
from crate.theme.rtd import __version__
from crate.theme.rtd.conf.furo import _html_page_context
from os import environ

source_suffix = ".rst"
Expand Down Expand Up @@ -103,6 +103,7 @@
# CrateDB General
'guide': ('https://cratedb.com/docs/guide/', None),
'crate-reference': ('https://cratedb.com/docs/crate/reference/en/latest/', None),
'ctk': ('https://cratedb-toolkit.readthedocs.io/', None),

# CrateDB Clients and Integrations
'crate-admin-ui': ('https://cratedb.com/docs/crate/admin-ui/en/latest/', None),
Expand Down Expand Up @@ -171,6 +172,8 @@
"https://unsplash.com/.*",
# [Errno 101] Network is unreachable
"https://www.gnu.org/.*",
# Temporary failure in name resolution
"https://jupysql.ploomber.io/.*",
]
linkcheck_anchors_ignore_for_url = [
# Requires JavaScript.
Expand Down Expand Up @@ -330,7 +333,7 @@ def apply_html_context_custom(app_inited):

# Modern / NG / Furo.
app.require_sphinx("3.0")
app.connect("html-page-context", _html_page_context)
app.connect("html-page-context", navigation.html_page_context)

# Customizations.
app.connect("builder-inited", configure_self_hosted_on_path)
Expand All @@ -347,4 +350,3 @@ def apply_html_context_custom(app_inited):
"parallel_write_safe": True,
"version": __version__,
}

54 changes: 0 additions & 54 deletions src/crate/theme/rtd/conf/furo.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<p class="sd-card-text">
<span class="fa fa-code fa-fw"></span>
&nbsp;
<a id="docs-feedback-open-github" class="feedback-compact-link" href="https://{{ github_host|default('github.com') }}/{{ github_user }}/{{ github_repo }}/{{ theme_vcs_pageview_mode|default('blob') }}/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}?plain=1" rel="noopener" target="_blank" title="View page source on GitHub">View&nbsp;page source</a>
<a id="docs-feedback-open-github" class="feedback-compact-link" href="https://{{ github_host|default('github.com') }}/{{ github_user }}/{{ github_repo }}/{{ theme_vcs_pageview_mode|default('blob') }}/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}?plain=true" rel="noopener" target="_blank" title="View page source on GitHub">View&nbsp;page source</a>
</p>
{% endif %}

Expand Down
9 changes: 9 additions & 0 deletions src/crate/theme/rtd/crate/components/googlesearch.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div role="complementary" class="bs-docs-sidebar hidden-print">
<div class="search-link">
{% if pagename == "search" %}
<a href="search.html" class="btn btn-primary">Search</a>
{% else %}
<a href="{{ pathto('search') }}" class="btn btn-primary">Search</a>
{% endif %}
</div>
</div>
16 changes: 12 additions & 4 deletions src/crate/theme/rtd/crate/sections/sidebar-primary.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@
<div class="sidebar-container">
<div class="sidebar-sticky">

<!-- Section 1
<!-- Section 1 + 2 -->
<div class="sidebar-tree">
{# {- ng_navigation_tree } #}
</div> -->
{{ ng_navigation_tree }}
</div>

<!-- Section 2 -->
{% if project == 'CrateDB documentation theme' %}

<!-- Section 3 -->
<span class="sd-text-center sd-fs-5 sd-font-weight-bold sd-text-uppercase sd-text-secondary">
Legacy navigation
</span>
{% include "sidebar.html" %}

{% endif %}

</div>
</div>
</div>
2 changes: 1 addition & 1 deletion src/crate/theme/rtd/crate/static/css/crateio-rtd.css
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ div.hero.danger {
}
.bs-docs-sidebar {
padding: 0px 20px 8px 16px;
margin-bottom: 20px;
/* margin-bottom: 20px; */
}

.affix {
Expand Down
5 changes: 5 additions & 0 deletions src/crate/theme/rtd/crate/static/css/ng/furo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,8 @@ article p:has(+ ul),
article p:has(+ ol) {
margin-bottom: 4px;
}

// Sidebar NG: Adjust margins.
.sidebar-tree {
margin-top: unset;
}