Skip to content

Commit e9a1ee1

Browse files
committed
✨ NEW: Add dt-past/dt-future class to item divs
1 parent a7cd3d3 commit e9a1ee1

File tree

4 files changed

+90
-15
lines changed

4 files changed

+90
-15
lines changed

docs/_static/custom.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/** highlight future events **/
2+
ol.timeline-default>li.timeline>div.tl-item.dt-future {
3+
outline-color: green;
4+
}
5+
16
/** furo and pydata-sphinx-theme **/
27
body[data-theme="dark"] {
38
--tl-dot-color: #9a9a9a;

docs/index.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ A scrolling horizontal timeline is created for HTML output, and other formats de
1717
name: 4th event
1818
- start: 2020-02-04
1919
name: 5th event
20-
- start: 2021-02-04
20+
- start: 2030-02-04
2121
name: 6th event
2222
---
2323
**{{dtrange}}**
@@ -161,7 +161,9 @@ class
161161
class-item
162162
: Classes to add to each item.
163163

164-
## CSS Variables
164+
## Customise HTML output
165+
166+
### CSS Variables
165167

166168
The following CSS variables can be used to customize the appearance of the timeline:
167169

@@ -211,3 +213,24 @@ body[data-theme="dark"] {
211213
}
212214
}
213215
```
216+
217+
### Data attributes
218+
219+
On the containing div for each event, the `data-dt` data attribute is added, which contains the event's `start` data/time in ISO format.
220+
JavaScript (if enabled) will also run, to add `dt-future` or `dt-past` class to each div, depending on whether the event is in the future or past.
221+
This means that you can use CSS selectors to style events based on their date/time.
222+
223+
For example, to highlight future events, you can add the following to your `conf.py`:
224+
225+
```python
226+
html_static_path = ["_static"]
227+
html_css_files = ["custom.css"]
228+
```
229+
230+
Then add to the CSS `_static/custom.css`:
231+
232+
```css
233+
ol.timeline-default>li.timeline>div.tl-item.dt-future {
234+
outline-color: green;
235+
}
236+
```

src/sphinx_timeline/main.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ def setup(app: Sphinx) -> None:
2525
"""Setup the extension."""
2626
from sphinx_timeline import __version__
2727

28-
app.connect("builder-inited", add_css)
28+
app.connect("builder-inited", add_html_assets)
29+
app.connect("html-page-context", load_html_assets)
2930
app.add_directive("timeline", TimelineDirective)
3031
app.add_node(
3132
TimelineDiv,
@@ -43,23 +44,47 @@ def setup(app: Sphinx) -> None:
4344
}
4445

4546

46-
def add_css(app: Sphinx):
47-
"""Copy the CSS to the build directory."""
47+
def add_html_assets(app: Sphinx) -> None:
48+
"""Add the HTML assets to the build directory."""
49+
if (not app.builder) or app.builder.format != "html":
50+
return
4851
# setup up new static path in output dir
4952
static_path = (Path(app.outdir) / "_sphinx_timeline_static").absolute()
5053
static_path.mkdir(exist_ok=True)
54+
for path in static_path.glob("**/*"):
55+
path.unlink()
5156
app.config.html_static_path.append(str(static_path))
52-
# Read the css content and hash it
53-
content = resources.read_text(static_module, "default.css")
54-
hash = hashlib.md5(content.encode("utf8")).hexdigest()
55-
# Write the css file
56-
css_path = static_path / f"tl_default.{hash}.css"
57-
app.add_css_file(css_path.name)
58-
if css_path.exists():
57+
for resource in resources.contents(static_module):
58+
if not resource.endswith(".css") and not resource.endswith(".js"):
59+
continue
60+
# Read the content and hash it
61+
content = resources.read_text(static_module, resource)
62+
hash = hashlib.md5(content.encode("utf8")).hexdigest()
63+
# Write the file
64+
name, ext = resource.split(".", maxsplit=1)
65+
write_path = static_path / f"{name}.{hash}.{ext}"
66+
write_path.write_text(content, encoding="utf8")
67+
68+
69+
def load_html_assets(app: Sphinx, pagename: str, *args, **kwargs) -> None:
70+
"""Ensure the HTML assets are loaded in the page, if necessary."""
71+
if (not app.builder) or app.builder.format != "html":
5972
return
60-
for path in static_path.glob("*.css"):
61-
path.unlink()
62-
css_path.write_text(content, encoding="utf8")
73+
if (not app.env) or not app.env.metadata.get(pagename, {}).get("timeline", False):
74+
return
75+
for resource in resources.contents(static_module):
76+
if not resource.endswith(".css") and not resource.endswith(".js"):
77+
continue
78+
# Read the content and hash it
79+
content = resources.read_text(static_module, resource)
80+
hash = hashlib.md5(content.encode("utf8")).hexdigest()
81+
# add the file to the context
82+
name, ext = resource.split(".", maxsplit=1)
83+
write_name = f"{name}.{hash}.{ext}"
84+
if ext == "css":
85+
app.add_css_file(write_name)
86+
if ext == "js":
87+
app.add_js_file(write_name)
6388

6489

6590
class TimelineDiv(nodes.General, nodes.Element):
@@ -251,6 +276,8 @@ def run(self) -> list[nodes.Element]:
251276
)
252277
item_node.append(item_container)
253278

279+
self.env.metadata[self.env.docname]["timeline"] = True
280+
254281
return [container]
255282

256283

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// On page load,
2+
// look for all divs with class "tl-item" and attribute "data-dt"
3+
// and a "dt-future" or "dt-past" class to each div, based on the current date.
4+
document.addEventListener("DOMContentLoaded", function () {
5+
const now = new Date();
6+
const nodes = document.querySelectorAll("div.tl-item[data-dt]");
7+
for (var i = 0, len = nodes.length; i < len; i++) {
8+
try {
9+
var dt = new Date(nodes[i].getAttribute("data-dt"));
10+
} catch (e) {
11+
console.warn(`Error parsing date: ${dt}`);
12+
continue;
13+
}
14+
if (dt > now) {
15+
nodes[i].classList.add("dt-future");
16+
} else {
17+
nodes[i].classList.add("dt-past");
18+
}
19+
}
20+
});

0 commit comments

Comments
 (0)