Skip to content

Commit db81eb9

Browse files
committed
Add "link tree" element, using directive linktree
1 parent 3663e0c commit db81eb9

File tree

16 files changed

+821
-1
lines changed

16 files changed

+821
-1
lines changed

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@
3030
## v0.2.0 - 2023-08-08
3131

3232
- For dropdown elements that should exclusively open when toggled,
33+
<<<<<<< HEAD
3334
add a `dropdown-group` CSS class. Thanks, @kojinkai and @msbt.
35+
=======
36+
add a `dropdown-group` CSS class
37+
- Add "link tree" element, using directive `linktree`
38+
>>>>>>> 1876b6b (Add "link tree" element, using directive `linktree`)
3439
3540
## v0.1.0 - 2023-07-19
3641

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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
"""Configuration file for the Sphinx documentation builder."""
22

33
import os
4+
import traceback
5+
import typing as t
6+
7+
from sphinx.application import Sphinx
8+
9+
from sphinx_design_elements.navigation import default_tree, demo_tree
410

511
project = "Sphinx Design Elements"
612
copyright = "2023-2024, Panodata Developers" # noqa: A001
@@ -23,6 +29,9 @@
2329
# html_logo = "_static/logo_wide.svg"
2430
# html_favicon = "_static/logo_square.svg"
2531

32+
# Add any paths that contain templates here, relative to this directory.
33+
templates_path = ["_templates"]
34+
2635
# if html_theme not in ("sphinx_book_theme", "pydata_sphinx_theme"):
2736
# html_css_files = [
2837
# "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"
@@ -33,6 +42,9 @@
3342
"sidebar_hide_name": False,
3443
}
3544

45+
# If true, `todo` and `todoList` produce output, else they produce nothing.
46+
todo_include_todos = True
47+
3648
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
3749
myst_enable_extensions = [
3850
"attrs_block",
@@ -64,3 +76,28 @@
6476
}
6577

6678
todo_include_todos = True
79+
80+
def setup(app: Sphinx) -> None:
81+
"""Set up the sphinx extension."""
82+
app.require_sphinx("3.0")
83+
app.connect("html-page-context", _html_page_context)
84+
85+
86+
def _html_page_context(
87+
app: Sphinx,
88+
pagename: str,
89+
templatename: str,
90+
context: t.Dict[str, t.Any],
91+
doctree: t.Any,
92+
) -> None:
93+
"""
94+
Sphinx HTML page context provider.
95+
"""
96+
97+
# Initialize link tree navigation component.
98+
try:
99+
context["sde_linktree_primary"] = default_tree(builder=app.builder, context=context).render()
100+
context["demo_synthetic_linktree"] = demo_tree(builder=app.builder, context=context).render()
101+
except Exception as ex:
102+
traceback.print_exception(ex)
103+
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
@@ -74,6 +74,7 @@ get_started
7474
gridtable
7575
infocard
7676
shield
77+
linktree
7778
```
7879

7980
```{toctree}
@@ -134,6 +135,13 @@ Badge generator for Shields\.io, with optional target linking.
134135
A versatile hyperlink generator.
135136
:::
136137

138+
:::{grid-item-card} {octicon}`workflow` Link tree
139+
:link: linktree
140+
:link-type: doc
141+
142+
A programmable toctree component.
143+
:::
144+
137145
:::{grid-item-card} {octicon}`tag` Special badges
138146
:link: tag
139147
: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
@@ -215,7 +215,7 @@ warn_unused_ignores = false
215215
warn_redundant_casts = true
216216

217217
[[tool.mypy.overrides]]
218-
module = [ "docutils.*" ]
218+
module = ["docutils.*", "furo.*"]
219219
ignore_missing_imports = true
220220

221221
[tool.versioningit.vcs]

sphinx_design_elements/compiled/style.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,10 @@ hr.docutils {
8888
.bottom-margin-generous {
8989
margin-bottom: 2em !important;
9090
}
91+
92+
/**
93+
* Fix appearance of page-rendered link tree.
94+
**/
95+
article .sidebar-tree p.caption {
96+
text-align: unset;
97+
}

sphinx_design_elements/extension.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .gridtable import setup_gridtable
1313
from .hyper import setup_hyper
1414
from .infocard import setup_infocard
15+
from .linktree import setup_linktree
1516
from .shield import setup_shield
1617
from .tag import setup_tags
1718

@@ -32,6 +33,7 @@ def setup_extension(app: Sphinx) -> None:
3233
setup_gridtable(app)
3334
setup_hyper(app)
3435
setup_infocard(app)
36+
setup_linktree(app)
3537
setup_shield(app)
3638
setup_tags(app)
3739

0 commit comments

Comments
 (0)