Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "link tree" element, using directive linktree #11

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
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: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ python:

sphinx:
builder: html
fail_on_warning: true
fail_on_warning: false
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- For dropdown elements that should exclusively open when toggled,
add a `dropdown-group` CSS class
- Add "link tree" element, using directive `linktree`

## v0.1.0 - 2023-07-19

Expand Down
9 changes: 9 additions & 0 deletions docs/_templates/linktree-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<h3>Classic toctree</h3>
<div class="sidebar-tree">
{{ sde_linktree_primary }}
</div>

<h3>Custom linktree</h3>
<div class="sidebar-tree">
{{ demo_synthetic_linktree }}
</div>
10 changes: 10 additions & 0 deletions docs/_templates/page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{%- extends "!page.html" %}

{% block content %}
{{ super() }}

{% if pagename == "linktree" %}
{% include "linktree-demo.html" %}
{% endif %}

{% endblock %}
39 changes: 39 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
"""Configuration file for the Sphinx documentation builder."""
import os
import traceback
import typing as t

from sphinx.application import Sphinx

from sphinx_design_elements.navigation import default_tree, demo_tree

project = "Sphinx Design Elements"
copyright = "2023, Panodata Developers" # noqa: A001
Expand All @@ -11,6 +17,7 @@
"sphinx_design",
"sphinx_design_elements",
"sphinx.ext.intersphinx",
"sphinx.ext.todo",
]

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

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# if html_theme not in ("sphinx_book_theme", "pydata_sphinx_theme"):
# html_css_files = [
# "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"
Expand All @@ -31,6 +41,9 @@
"sidebar_hide_name": False,
}

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True

exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
myst_enable_extensions = [
"attrs_block",
Expand Down Expand Up @@ -60,3 +73,29 @@
"sd": ("https://sphinx-design.readthedocs.io/en/latest/", None),
"myst": ("https://myst-parser.readthedocs.io/en/latest/", None),
}


def setup(app: Sphinx) -> None:
"""Set up the sphinx extension."""
app.require_sphinx("3.0")
app.connect("html-page-context", _html_page_context)


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.
"""

# Initialize link tree navigation component.
try:
context["sde_linktree_primary"] = default_tree(builder=app.builder, context=context).render()
context["demo_synthetic_linktree"] = demo_tree(builder=app.builder, context=context).render()
except Exception as ex:
traceback.print_exception(ex)
raise
1 change: 1 addition & 0 deletions docs/get_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ provided by this collection, and how to use them in your documentation markup.

- [](#gridtable-directive)
- [](#infocard-directive)
- [](#linktree-directive)
- [](#tag-role)

Both [reStructuredText] and [Markedly Structured Text] syntax are supported equally well.
Expand Down
8 changes: 8 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ get_started

gridtable
infocard
linktree
```

```{toctree}
Expand Down Expand Up @@ -118,6 +119,13 @@ HTML table based on a grid layout, with ergonomic top-down configuration.
Composite info card container element, to be used as a grid item.
:::

:::{grid-item-card} {octicon}`workflow` Link tree
:link: linktree
:link-type: doc

A programmable toctree component.
:::

:::{grid-item-card} {octicon}`tag` Special badges
:link: tag
:link-type: doc
Expand Down
128 changes: 128 additions & 0 deletions docs/linktree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
(linktree-directive)=

# Link Tree


## About

Similar but different from a Toc Tree.

```{attention}
This component is a work in progress. Breaking changes should be expected until a
1.0 release, so version pinning is recommended.
```

### Problem

So much work went into the toctree mechanics, it is sad that it is not a reusable
component for building any kinds of navigation structures, and to be able to define
its contents more freely.

### Solution

This component implements a programmable toc tree component, the link tree.


## Details

The link tree component builds upon the Sphinx [toc] and [toctree] subsystem. It provides
both a rendered primary navigation within the `sde_linktree_primary` context variable
for use from HTML templates, and a Sphinx directive, `linktree`, for rendering
navigation trees into pages, similar but different from the [toctree directive]. The
user interface mechanics and styles are based on [Furo]'s primary sidebar component.


## Customizing

Link trees can be customized by creating them programmatically, similar to how
the `sde_linktree_primary` context variable is populated with the default Sphinx
toc tree.

The section hidden behind the dropdown outlines how the "custom linktree" is
defined, which is displayed at the bottom of the page in a rendered variant.
:::{dropdown} Custom linktree example code

```python
import typing as t

from sphinx.application import Sphinx
from sphinx_design_elements.lib.linktree import LinkTree


def demo_tree(app: Sphinx, context: t.Dict[str, t.Any], docname: str = None) -> LinkTree:
"""
The demo link tree showcases some features what can be done.

It uses regular page links to documents in the current project, a few
intersphinx references, and a few plain, regular, URL-based links.
"""
linktree = LinkTree.from_context(app=app, context=context)
doc = linktree.api.doc
ref = linktree.api.ref
link = linktree.api.link

linktree \
.title("Project-local page links") \
.add(
doc(name="gridtable"),
doc(name="infocard"),
)

linktree \
.title("Intersphinx links") \
.add(
ref("sd:index"),
ref("sd:badges", label="sphinx{design} badges"),
ref("myst:syntax/images_and_figures", "MyST » Images and figures"),
ref("myst:syntax/referencing", "MyST » Cross references"),
)

linktree \
.title("URL links") \
.add(
link(uri="https://example.com"),
link(uri="https://example.com", label="A link to example.com, using a custom label ⚽."),
)

return linktree
```
:::

```{todo}
- Use the `linktree` directive to define custom link trees.
- Link to other examples of custom link trees.
- Maybe use `:link:` and `:link-type:` directive options of `grid-item-card` directive.
```


## Directive examples

### Example 1

The link tree of the `index` page, using a defined maximum depth, and a custom title.
```{linktree}
:docname: index
:maxdepth: 1
:title: Custom title
```
Comment on lines +102 to +107
Copy link
Member Author

Choose a reason for hiding this comment

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

Needs to be completed by using a custom MyST markup to define the content items of a linktree element.



## Appendix

Here, at the bottom of the page, different global template variables are presented,
which contain representations of navigation trees, rendered to HTML.

- `sde_linktree_primary`: The classic toctree, like it will usually be rendered
into the primary sidebar.
- `demo_synthetic_linktree`: A customized link tree composed of links to project-local
pages, intersphinx links, and URLs, for demonstration purposes.

```{hint}
The corresponding template, `linktree-demo.html` will exclusively be rendered
here, and not on other pages.
```

[Furo]: https://pradyunsg.me/furo/
[toctree directive]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-toctree
[toc]: https://www.sphinx-doc.org/en/master/development/templating.html#toc
[toctree]: https://www.sphinx-doc.org/en/master/development/templating.html#toctree
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ warn_unused_ignores = true
warn_redundant_casts = true

[[tool.mypy.overrides]]
module = ["docutils.*"]
module = ["docutils.*", "furo.*"]
ignore_missing_imports = true

[tool.pytest.ini_options]
Expand Down
8 changes: 8 additions & 0 deletions sphinx_design_elements/compiled/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,11 @@
margin-top: unset;
margin-bottom: unset;
}


/**
* Fix appearance of page-rendered link tree.
**/
article .sidebar-tree p.caption {
text-align: unset;
}
4 changes: 4 additions & 0 deletions sphinx_design_elements/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
from .dropdown_group import setup_dropdown_group
from .gridtable import setup_gridtable
from .infocard import setup_infocard
from .linktree import setup_linktree
from .tag import setup_tags


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

app.require_sphinx("3.0")

app.connect("builder-inited", update_css_js)
app.connect("env-updated", update_css_links)
# we override container html visitors, to stop the default behaviour
Expand All @@ -27,6 +30,7 @@ def setup_extension(app: Sphinx) -> None:
setup_infocard(app)
setup_tags(app)
setup_dropdown_group(app)
setup_linktree(app)


def update_css_js(app: Sphinx):
Expand Down
Empty file.
Loading