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

Tutorials page alternative #3230

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
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
35 changes: 35 additions & 0 deletions docs/_static/js/tutorial_filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
document.addEventListener("DOMContentLoaded", function() {
const filterButtons = document.querySelectorAll(".filter-btn");
const cards = document.querySelectorAll(".tutorial-card");

let activeFilters = new Set();

filterButtons.forEach(button => {
button.addEventListener("click", () => {
const filter = button.dataset.filter;

if (filter === "all") {
activeFilters.clear();
} else {
if (activeFilters.has(filter)) {
activeFilters.delete(filter);
} else {
activeFilters.add(filter);
}
}

// Toggle "active" class for styling
button.classList.toggle("active");

// Display cards based on active filters
cards.forEach(card => {
const cardTags = card.dataset.tags.split(", ");
if (activeFilters.size === 0 || [...activeFilters].every(f => cardTags.includes(f))) {
card.style.display = "";
} else {
card.style.display = "none";
}
});
});
});
});
2 changes: 2 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"sphinx_design",
"sphinxext.opengraph",
"hoverxref.extension",
"scvi_tutorials",
]


Expand Down Expand Up @@ -156,6 +157,7 @@
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_css_files = ["css/override.css"]
html_js_files = ["js/tutorial_filter.js"]
html_show_sphinx = False


Expand Down
168 changes: 168 additions & 0 deletions docs/scvi_tutorials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
from docutils import nodes
from docutils.parsers.rst import directives
from sphinx.util.docutils import SphinxDirective


class TutorialCardNode(nodes.General, nodes.Element):
"""Node for a single tutorial card."""

pass


class TutorialListNode(nodes.General, nodes.Element):
"""Node for a list of tutorial cards."""

pass


class TutorialCardDirective(SphinxDirective):
"""
Directive to create a tutorial card.

Options
-------
title : str
The title of the tutorial card.
description : str
The description of the tutorial card.
tags : str
The tags associated with the tutorial card.
notebook : str
The link to the notebook for the tutorial card.
"""

option_spec = {
"title": directives.unchanged,
"description": directives.unchanged,
"tags": directives.unchanged,
"notebook": directives.unchanged,
}

def run(self):
"""
Create a new TutorialCardNode and append it to the

environment's all_tutorial_cards list.
"""
env = self.state.document.settings.env
if not hasattr(env, "all_tutorial_cards"):
env.all_tutorial_cards = []

title = self.options.get("title", "No Title")
description = self.options.get("description", "")
tags = self.options.get("tags", "")
notebook = self.options.get("notebook", "")

card_node = TutorialCardNode()
card_node["title"] = title
card_node["description"] = description
card_node["tags"] = tags
card_node["notebook"] = notebook

env.all_tutorial_cards.append(card_node)
return [card_node]


class TutorialListDirective(SphinxDirective):
"""Directive to create a list of tutorial cards."""

def run(self):
"""Create a new TutorialListNode."""
return [TutorialListNode("")]


def process_tutorial_cards(app, doctree, fromdocname):
"""
Process all TutorialCardNodes and TutorialListNodes in the doctree and

replace them with the rendered HTML.

Parameters
----------
app : Sphinx application object
The Sphinx application object.
doctree : docutils.nodes.document
The doctree object.
fromdocname : str
The name of the document.
"""
env = app.builder.env
if not hasattr(env, "all_tutorial_cards"):
return

for node in doctree.traverse(TutorialListNode):
container = nodes.container()

# Render Filter Buttons
filter_buttons = """
<div id="filter-buttons">
<button class="filter-btn" data-filter="all">All</button>
"""
tags_set = set()
for card_node in env.all_tutorial_cards:
for tag in card_node["tags"].split(", "):
tags_set.add(tag)
for tag in sorted(tags_set):
filter_buttons += f'<button class="filter-btn" data-filter="{tag}">{tag}</button>'
filter_buttons += "</div>"

container.append(nodes.raw("", filter_buttons, format="html"))

# Render Tutorial Cards
tutorial_list_html = '<div id="tutorial-cards">'
for card_node in env.all_tutorial_cards:
tutorial_list_html += f'''
<div class="tutorial-card" data-tags="{card_node["tags"]}">
<h3><a href="{card_node["notebook"]}">{card_node["title"]}</a></h3>
<p>{card_node["description"]}</p>
<p><strong>Tags:</strong> {card_node["tags"]}</p>
</div>
'''
tutorial_list_html += "</div>"

container.append(nodes.raw("", tutorial_list_html, format="html"))

node.replace_self(container)


def visit_tutorial_card_node(self, node):
"""
Visit a TutorialCardNode.

Parameters
----------
self : HTMLTranslator
The HTML translator.
node : TutorialCardNode
The tutorial card node.
"""
self.body.append(self.starttag(node, "div", CLASS="tutorial-card"))


def depart_tutorial_card_node(self, node):
"""
Depart a TutorialCardNode.

Parameters
----------
self : HTMLTranslator
The HTML translator.
node : TutorialCardNode
The tutorial card node.
"""
self.body.append("</div>")


def setup(app):
"""
App setup hook.

Parameters
----------
app : Sphinx application object
The Sphinx application object.
"""
app.add_node(TutorialCardNode, html=(visit_tutorial_card_node, depart_tutorial_card_node))
app.add_directive("tutorialcard", TutorialCardDirective)
app.add_directive("tutoriallist", TutorialListDirective)
app.connect("doctree-resolved", process_tutorial_cards)
22 changes: 22 additions & 0 deletions docs/testing/cards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Tutorial Cards

```{tutorialcard}
:title: Atlas-level integration of lung data
:description: testing testing desciption
:tags: Integration, Analysis
:notebook: ../notebooks/scrna/harmonization
```

```{tutorialcard}
:title: Reference mapping with scvi-tools
:description: testing testing desciption
:tags: Reference Mapping, Analysis
:notebook: ../notebooks/scrna/scarches_scvi_tools
```

```{tutorialcard}
:title: PeakVI: Analyzing scATACseq data
:description: testing testing desciption
:tags: Analysis, Differential Analysis
:notebook: ../notebooks/atac/PeakVI
```
4 changes: 4 additions & 0 deletions docs/testing/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Testing

```{tutoriallist}
```
Loading