Skip to content

Commit 109cac2

Browse files
authored
Merge pull request #11 from eScholarship/10-table-of-contents-navigation
table of contents navigation
2 parents 59b3ce9 + 6f37cab commit 109cac2

3 files changed

Lines changed: 125 additions & 1 deletion

File tree

lib/ucpec_static/tei/elements/body.rb

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,85 @@ module UCPECStatic
44
module TEI
55
module Elements
66
class Body < UCPECStatic::TEI::Nodes::Element
7+
before_prepare_html :collect_chapters!
8+
9+
around_render_children :render_with_toc!
10+
711
matches_tei_tag! "body"
812

913
uses_html_tag! :section
14+
15+
# @return [Array<Hash>]
16+
attr_reader :chapters
17+
18+
# Check if there are any chapters to display in ToC
19+
def has_chapters?
20+
chapters.any?
21+
end
22+
23+
private
24+
25+
# Collect all div elements with type="chapter" (div1, div2, etc.)
26+
# @return [void]
27+
def collect_chapters!
28+
@chapters = []
29+
30+
# Traverse all descendants to find any division element with type="chapter"
31+
traverse do |node|
32+
next unless node.kind_of?(Elements::Division)
33+
next unless node.xml_attributes["type"] == "chapter"
34+
35+
chapter_id = node.xml_attributes["id"]
36+
next if chapter_id.blank?
37+
38+
# Find the heading within this chapter
39+
heading = node.find_first_descendant { |child| child.kind_of?(Elements::Heading) }
40+
next unless heading
41+
42+
# Extract the heading text
43+
heading_text = extract_heading_text(heading)
44+
45+
@chapters << {
46+
id: chapter_id,
47+
title: heading_text,
48+
level: node.level
49+
}
50+
end
51+
end
52+
53+
# Extract text content from a heading node
54+
# @param [UCPECStatic::TEI::Nodes::Element] heading
55+
# @return [String]
56+
def extract_heading_text(heading)
57+
heading.node.text.strip
58+
end
59+
60+
# Render table of contents before children
61+
# @return [void]
62+
def render_with_toc!
63+
render_table_of_contents! if has_chapters?
64+
yield
65+
end
66+
67+
# Render the table of contents navigation
68+
# @return [void]
69+
def render_table_of_contents!
70+
wrap_with_tag!("nav", class: "table-of-contents") do
71+
wrap_with_tag!("h1", class: "toc-title") do
72+
html_builder.text "Table of Contents"
73+
end
74+
75+
wrap_with_tag!("ol", class: "toc-list") do
76+
chapters.each do |chapter|
77+
wrap_with_tag!("li", class: "toc-item") do
78+
wrap_with_tag!("a", href: "##{chapter[:id]}", class: "toc-link") do
79+
html_builder.text chapter[:title]
80+
end
81+
end
82+
end
83+
end
84+
end
85+
end
1086
end
1187
end
1288
end

spec/data/sample-tei.html

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,32 @@ <h1>The Hellenistic Settlements in Europe, the Islands, and Asia Minor</h1>
77
<div data-tei-tag="docImprint"><span data-tei-tag="publisher">UNIVERSITY OF CALIFORNIA PRESS</span><span data-tei-tag="pubPlace">Berkeley · Los Angeles · Oxford</span><time data-tei-tag="docDate">1996</time></div>
88
</div>
99
</header>
10-
<section data-tei-tag="body">
10+
<section data-tei-tag="body"><nav class="table-of-contents">
11+
<h1 class="toc-title">Table of Contents</h1>
12+
<ol class="toc-list">
13+
<li class="toc-item"><a href="#d0e111" class="toc-link">The Scholarship and the Sources</a></li>
14+
<li class="toc-item"><a href="#d0e796" class="toc-link">Introduction</a></li>
15+
<li class="toc-item"><a href="#d0e3680" class="toc-link">I Illyria and Epirus</a></li>
16+
<li class="toc-item"><a href="#d0e4087" class="toc-link">II Thrace</a></li>
17+
<li class="toc-item"><a href="#d0e4913" class="toc-link">III Macedonia and Paeonia</a></li>
18+
<li class="toc-item"><a href="#d0e6850" class="toc-link">IV Thessaly, Aetolia, and Boeotia</a></li>
19+
<li class="toc-item"><a href="#d0e8237" class="toc-link">V The Peloponnese</a></li>
20+
<li class="toc-item"><a href="#d0e9000" class="toc-link">VI The Islands</a></li>
21+
<li class="toc-item"><a href="#d0e10071" class="toc-link">VII The Troad</a></li>
22+
<li class="toc-item"><a href="#d0e11686" class="toc-link">VIII Mysia and Aeolis</a></li>
23+
<li class="toc-item"><a href="#d0e12900" class="toc-link">IX Ionia</a></li>
24+
<li class="toc-item"><a href="#d0e14550" class="toc-link">X Lydia</a></li>
25+
<li class="toc-item"><a href="#d0e20532" class="toc-link">XI Caria</a></li>
26+
<li class="toc-item"><a href="#d0e24224" class="toc-link">XII Phrygia</a></li>
27+
<li class="toc-item"><a href="#d0e30625" class="toc-link">XIII Lycia</a></li>
28+
<li class="toc-item"><a href="#d0e30899" class="toc-link">XIV Pamphylia</a></li>
29+
<li class="toc-item"><a href="#d0e31740" class="toc-link">XV Pisidia and Lycaonia</a></li>
30+
<li class="toc-item"><a href="#d0e32521" class="toc-link">XVI Cilicia</a></li>
31+
<li class="toc-item"><a href="#d0e35047" class="toc-link">XVII Cappadocia and Galatia</a></li>
32+
<li class="toc-item"><a href="#d0e35773" class="toc-link">XVIII Pontus and Paphlagonia</a></li>
33+
<li class="toc-item"><a href="#d0e36491" class="toc-link">XIX Bithynia</a></li>
34+
</ol>
35+
</nav>
1136
<div id="d0e111" data-tei-tag="div1" data-type="chapter">
1237
<h1 class="Heading-Heading2B"><a href="#d0e111" class="heading-link">The Scholarship and the Sources</a></h1>
1338
<div id="d0e115" data-tei-tag="div2" data-type="ss1">

templates/styles.css

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,29 @@ section[data-tei-tag="body"] a[data-tei-tag="ref"]:hover {
336336
box-shadow: 0 2px 4px rgba(231, 76, 60, 0.3);
337337
}
338338

339+
/* Table of Contents Styling */
340+
.table-of-contents {
341+
margin: 2rem 0 3rem 0;
342+
}
343+
344+
.toc-item {
345+
margin: 0.75rem 1rem 0;
346+
font-weight: bold;
347+
}
348+
349+
.toc-link {
350+
color: unset;
351+
text-decoration: none;
352+
transition: all 0.3s ease;
353+
display: inline-block;
354+
padding: 0.25rem 0.5rem;
355+
}
356+
357+
.toc-link:hover {
358+
transform: translateX(5px);
359+
text-decoration: underline;
360+
}
361+
339362
/* Scroll behavior for smooth jumping */
340363
html {
341364
scroll-behavior: smooth;

0 commit comments

Comments
 (0)