Skip to content

Commit 180c4f7

Browse files
authored
feat: add TOC as last slide (#193)
1 parent 4606df6 commit 180c4f7

File tree

5 files changed

+158
-2
lines changed

5 files changed

+158
-2
lines changed

.reveal-md/styles.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,13 @@
99
* {
1010
font-family: Helvetica, sans-serif !important;
1111
}
12+
13+
.table-of-contents h1 {
14+
font-size: 16px;
15+
}
16+
.table-of-contents {
17+
max-height: 95%;
18+
overflow-y: scroll;
19+
overflow: -moz-scrollbars-vertical;
20+
font-size: 14px;
21+
}

plugins.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
options.dependencies = options.dependencies || [];
2+
3+
options.dependencies.push(
4+
// https://github.com/naamor/reveal.js-tableofcontents
5+
{ src: "_assets/plugins/tableofcontents.js" }
6+
);

plugins/tableofcontents.js

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/**
2+
* Originally it's
3+
*
4+
* reveal.js table of contents plugin
5+
*
6+
* A plugin which generates automatically a table of contents slide.
7+
*
8+
* Demo https://naamor.github.io/reveal.js-tableofcontents/
9+
*
10+
* MIT License
11+
* Copyright (c) 2018 Roman Stocker
12+
*
13+
* Modified in 2023 by @vvscod as it doesn't support markdown
14+
* https://github.com/naamor/reveal.js-tableofcontents/issues/2
15+
*/
16+
17+
var RevealTableOfContents =
18+
window.RevealTableOfContents ||
19+
(() => {
20+
// Set all option defaults
21+
const options = Reveal.getConfig().tableofcontents || {};
22+
const titleTag = options.titleTag || "h1";
23+
let titleTagSelector = ["h1", "h2", "h3", "h4", "h5", "h6"];
24+
let title = options.title || "Table of Contents";
25+
const position = options.position || 2;
26+
const fadeInElements = options.fadeInElements || false;
27+
28+
let ignoreFirstSlide = options.ignoreFirstSlide;
29+
if (typeof ignoreFirstSlide === "undefined") ignoreFirstSlide = true;
30+
31+
initialize();
32+
33+
function initialize() {
34+
if (typeof options.titleTagSelector === "string") {
35+
titleTagSelector = options.titleTagSelector
36+
.split(",")
37+
.map((item) => item.trim());
38+
}
39+
40+
generateTableOfContentsSlide();
41+
}
42+
43+
function generateTableOfContentsSlide() {
44+
const slides = document.getElementsByClassName("slides")[0];
45+
46+
const section = document.createElement("section");
47+
section.className = "table-of-contents";
48+
49+
const heading = document.createElement(titleTag);
50+
heading.innerText = title;
51+
section.appendChild(heading);
52+
53+
const list = generateList();
54+
section.appendChild(list);
55+
56+
// Subtract by one because index starts with zero
57+
const slideAfter = slides.children[position - 1];
58+
59+
// Check if there are enough slides for the configured table of contents slide position
60+
// or set the table of contents slide automatically after the last slide
61+
if (slideAfter !== undefined) {
62+
slides.insertBefore(section, slideAfter);
63+
} else {
64+
slides.appendChild(section);
65+
}
66+
}
67+
68+
// Generate list with the title of each slide
69+
function generateList() {
70+
const slides = Reveal.getSlides();
71+
72+
const ul = document.createElement("ul");
73+
74+
let counter = 0;
75+
76+
// Ignore first slide with counter 0
77+
if (ignoreFirstSlide) {
78+
counter++;
79+
}
80+
81+
for (counter; counter < slides.length; counter++) {
82+
const title = getTitle(slides[counter]);
83+
84+
if (title !== undefined) {
85+
const li = document.createElement("li");
86+
87+
// Add attributes for use reveal.js fragment functionality
88+
if (fadeInElements) {
89+
li.className = "fragment";
90+
li.setAttribute("data-fragment-index", counter);
91+
}
92+
93+
li.innerHTML = title;
94+
95+
ul.appendChild(li);
96+
}
97+
}
98+
99+
return ul;
100+
}
101+
102+
// Select the text of the most important heading tag of every slide
103+
function getTitle({ childNodes }) {
104+
return (title = Array.from(childNodes)
105+
.filter(getSlideTitle)
106+
.map(getSlideTitle)[0]);
107+
}
108+
109+
// Filter tags based on options
110+
function getSlideTitle(element) {
111+
const { tagName, textContent } = element;
112+
if (tagName === undefined) {
113+
return false;
114+
}
115+
116+
const originalTitle =
117+
titleTagSelector.includes(tagName.toLowerCase()) && textContent;
118+
119+
if (originalTitle) {
120+
return originalTitle;
121+
}
122+
if (element.matches('script[type="text/template"]')) {
123+
const markdownLinksRegexp = /\[(.*?)\]\((.*?)\)/g;
124+
return (
125+
element.innerHTML
126+
.trim()
127+
.split("\n")
128+
.filter((line) => line.trim().startsWith("#"))
129+
.map((line) => line.replaceAll("#", "").trim())
130+
.map((line) => line.replace(markdownLinksRegexp, ""))
131+
.join(". ") || undefined
132+
);
133+
}
134+
}
135+
})();

reveal-md.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
"theme": "white",
55
"watch": true,
66
"css": ".reveal-md/styles.css",
7-
"listingTemplate": ".reveal-md/listing.html"
7+
"listingTemplate": ".reveal-md/listing.html",
8+
"scripts": ["plugins.js"]
89
}

reveal.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@
33
"hash": true,
44
"history": false,
55
"backgroundTransition": "fade",
6-
"width": "80%"
6+
"width": "80%",
7+
"tableofcontents": {
8+
"title": "План",
9+
"position": 1000
10+
}
711
}

0 commit comments

Comments
 (0)