Skip to content

Commit 393a62c

Browse files
committed
Add "link tree" element, using directive linktree
1 parent 3732d10 commit 393a62c

File tree

16 files changed

+825
-1
lines changed

16 files changed

+825
-1
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log
22

3+
## Unreleased
4+
5+
- Add "link tree" element, using directive `linktree`
6+
37
## v0.1.0 - 2023-07-19
48

59
- Add "grid table" element, using directives `sd-table`, `sd-row`, `sd-item`

docs/_templates/linktree-demo.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<h3>Classic toctree</h3>
2+
<div class="sidebar-tree">
3+
{{ sde_linktree_primary }}
4+
</div>
5+
6+
<h3>Custom linktree</h3>
7+
<div class="sidebar-tree">
8+
{{ demo_synthetic_linktree }}
9+
</div>

docs/_templates/page.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{%- extends "!page.html" %}
2+
3+
{% block content %}
4+
{{ super() }}
5+
6+
{% if pagename == "linktree" %}
7+
{% include "linktree-demo.html" %}
8+
{% endif %}
9+
10+
{% endblock %}

docs/conf.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
"""Configuration file for the Sphinx documentation builder."""
22
import os
3+
import traceback
4+
import typing as t
5+
6+
from sphinx.application import Sphinx
7+
8+
from sphinx_design_elements.navigation import default_tree, demo_tree
39

410
project = "Sphinx Design Elements"
511
copyright = "2023, Panodata Developers" # noqa: A001
@@ -11,6 +17,7 @@
1117
"sphinx_design",
1218
"sphinx_design_elements",
1319
"sphinx.ext.intersphinx",
20+
"sphinx.ext.todo",
1421
]
1522

1623
html_theme = os.environ.get("SPHINX_THEME", "furo")
@@ -21,6 +28,9 @@
2128
# html_logo = "_static/logo_wide.svg"
2229
# html_favicon = "_static/logo_square.svg"
2330

31+
# Add any paths that contain templates here, relative to this directory.
32+
templates_path = ["_templates"]
33+
2434
# if html_theme not in ("sphinx_book_theme", "pydata_sphinx_theme"):
2535
# html_css_files = [
2636
# "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"
@@ -31,6 +41,9 @@
3141
"sidebar_hide_name": False,
3242
}
3343

44+
# If true, `todo` and `todoList` produce output, else they produce nothing.
45+
todo_include_todos = True
46+
3447
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
3548
myst_enable_extensions = [
3649
"attrs_block",
@@ -60,3 +73,29 @@
6073
"sd": ("https://sphinx-design.readthedocs.io/en/latest/", None),
6174
"myst": ("https://myst-parser.readthedocs.io/en/latest/", None),
6275
}
76+
77+
78+
def setup(app: Sphinx) -> None:
79+
"""Set up the sphinx extension."""
80+
app.require_sphinx("3.0")
81+
app.connect("html-page-context", _html_page_context)
82+
83+
84+
def _html_page_context(
85+
app: Sphinx,
86+
pagename: str,
87+
templatename: str,
88+
context: t.Dict[str, t.Any],
89+
doctree: t.Any,
90+
) -> None:
91+
"""
92+
Sphinx HTML page context provider.
93+
"""
94+
95+
# Initialize link tree navigation component.
96+
try:
97+
context["sde_linktree_primary"] = default_tree(builder=app.builder, context=context).render()
98+
context["demo_synthetic_linktree"] = demo_tree(builder=app.builder, context=context).render()
99+
except Exception as ex:
100+
traceback.print_exception(ex)
101+
raise

docs/get_started.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ provided by this collection, and how to use them in your documentation markup.
6464

6565
- [](#gridtable-directive)
6666
- [](#infocard-directive)
67+
- [](#linktree-directive)
6768
- [](#tag-role)
6869

6970
Both [reStructuredText] and [Markedly Structured Text] syntax are supported equally well.

docs/index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ get_started
7373
7474
gridtable
7575
infocard
76+
linktree
7677
```
7778

7879
```{toctree}
@@ -117,6 +118,13 @@ HTML table based on a grid layout, with ergonomic top-down configuration.
117118
Composite info card container element, to be used as a grid item.
118119
:::
119120

121+
:::{grid-item-card} {octicon}`workflow` Link tree
122+
:link: linktree
123+
:link-type: doc
124+
125+
A programmable toctree component.
126+
:::
127+
120128
:::{grid-item-card} {octicon}`tag` Special badges
121129
:link: tag
122130
:link-type: doc

docs/linktree.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
(linktree-directive)=
2+
3+
# Link Tree
4+
5+
6+
## About
7+
8+
Similar but different from a Toc Tree.
9+
10+
```{attention}
11+
This component is a work in progress. Breaking changes should be expected until a
12+
1.0 release, so version pinning is recommended.
13+
```
14+
15+
### Problem
16+
17+
So much work went into the toctree mechanics, it is sad that it is not a reusable
18+
component for building any kinds of navigation structures, and to be able to define
19+
its contents more freely.
20+
21+
### Solution
22+
23+
This component implements a programmable toc tree component, the link tree.
24+
25+
26+
## Details
27+
28+
The link tree component builds upon the Sphinx [toc] and [toctree] subsystem. It provides
29+
both a rendered primary navigation within the `sde_linktree_primary` context variable
30+
for use from HTML templates, and a Sphinx directive, `linktree`, for rendering
31+
navigation trees into pages, similar but different from the [toctree directive]. The
32+
user interface mechanics and styles are based on [Furo]'s primary sidebar component.
33+
34+
35+
## Customizing
36+
37+
Link trees can be customized by creating them programmatically, similar to how
38+
the `sde_linktree_primary` context variable is populated with the default Sphinx
39+
toc tree.
40+
41+
The section hidden behind the dropdown outlines how the "custom linktree" is
42+
defined, which is displayed at the bottom of the page in a rendered variant.
43+
:::{dropdown} Custom linktree example code
44+
45+
```python
46+
import typing as t
47+
48+
from sphinx.application import Sphinx
49+
from sphinx_design_elements.lib.linktree import LinkTree
50+
51+
52+
def demo_tree(app: Sphinx, context: t.Dict[str, t.Any], docname: str = None) -> LinkTree:
53+
"""
54+
The demo link tree showcases some features what can be done.
55+
56+
It uses regular page links to documents in the current project, a few
57+
intersphinx references, and a few plain, regular, URL-based links.
58+
"""
59+
linktree = LinkTree.from_context(app=app, context=context)
60+
doc = linktree.api.doc
61+
ref = linktree.api.ref
62+
link = linktree.api.link
63+
64+
linktree \
65+
.title("Project-local page links") \
66+
.add(
67+
doc(name="gridtable"),
68+
doc(name="infocard"),
69+
)
70+
71+
linktree \
72+
.title("Intersphinx links") \
73+
.add(
74+
ref("sd:index"),
75+
ref("sd:badges", label="sphinx{design} badges"),
76+
ref("myst:syntax/images_and_figures", "MyST » Images and figures"),
77+
ref("myst:syntax/referencing", "MyST » Cross references"),
78+
)
79+
80+
linktree \
81+
.title("URL links") \
82+
.add(
83+
link(uri="https://example.com"),
84+
link(uri="https://example.com", label="A link to example.com, using a custom label ⚽."),
85+
)
86+
87+
return linktree
88+
```
89+
:::
90+
91+
```{todo}
92+
- Use the `linktree` directive to define custom link trees.
93+
- Link to other examples of custom link trees.
94+
- Maybe use `:link:` and `:link-type:` directive options of `grid-item-card` directive.
95+
```
96+
97+
98+
## Directive examples
99+
100+
### Example 1
101+
102+
The link tree of the `index` page, using a defined maximum depth, and a custom title.
103+
```{linktree}
104+
:docname: index
105+
:maxdepth: 1
106+
:title: Custom title
107+
```
108+
109+
110+
## Appendix
111+
112+
Here, at the bottom of the page, different global template variables are presented,
113+
which contain representations of navigation trees, rendered to HTML.
114+
115+
- `sde_linktree_primary`: The classic toctree, like it will usually be rendered
116+
into the primary sidebar.
117+
- `demo_synthetic_linktree`: A customized link tree composed of links to project-local
118+
pages, intersphinx links, and URLs, for demonstration purposes.
119+
120+
```{hint}
121+
The corresponding template, `linktree-demo.html` will exclusively be rendered
122+
here, and not on other pages.
123+
```
124+
125+
[Furo]: https://pradyunsg.me/furo/
126+
[toctree directive]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-toctree
127+
[toc]: https://www.sphinx-doc.org/en/master/development/templating.html#toc
128+
[toctree]: https://www.sphinx-doc.org/en/master/development/templating.html#toctree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ warn_unused_ignores = true
116116
warn_redundant_casts = true
117117

118118
[[tool.mypy.overrides]]
119-
module = ["docutils.*"]
119+
module = ["docutils.*", "furo.*"]
120120
ignore_missing_imports = true
121121

122122
[tool.pytest.ini_options]

sphinx_design_elements/compiled/style.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,11 @@
6161
margin-top: unset;
6262
margin-bottom: unset;
6363
}
64+
65+
66+
/**
67+
* Fix appearance of page-rendered link tree.
68+
**/
69+
article .sidebar-tree p.caption {
70+
text-align: unset;
71+
}

sphinx_design_elements/extension.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@
1010
from . import compiled as static_module
1111
from .gridtable import setup_gridtable
1212
from .infocard import setup_infocard
13+
from .linktree import setup_linktree
1314
from .tag import setup_tags
1415

1516

1617
def setup_extension(app: Sphinx) -> None:
1718
"""Set up the sphinx extension."""
1819

20+
app.require_sphinx("3.0")
21+
1922
app.connect("builder-inited", update_css_js)
2023
app.connect("env-updated", update_css_links)
2124
# we override container html visitors, to stop the default behaviour
@@ -25,6 +28,7 @@ def setup_extension(app: Sphinx) -> None:
2528
setup_gridtable(app)
2629
setup_infocard(app)
2730
setup_tags(app)
31+
setup_linktree(app)
2832

2933

3034
def update_css_js(app: Sphinx):

0 commit comments

Comments
 (0)