Skip to content

Commit c891a3b

Browse files
jeremymanningclaude
andcommitted
Add sidebar navigation to HTML CV
- Add fixed sidebar with section links for quick navigation - Fix download button hover color (lighter green tint) - Add scroll-margin-top so section titles visible when navigating - Hide sidebar on screens <1200px and in print - Sidebar aligns with CV container top 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 9c25bbe commit c891a3b

File tree

4 files changed

+138
-2
lines changed

4 files changed

+138
-2
lines changed

css/cv.css

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@
4343
:root {
4444
--primary-green: rgb(0, 105, 62);
4545
--bg-green: rgba(0, 105, 62, 0.2);
46+
--bg-green-light: rgba(0, 112, 60, 0.15);
47+
--hover-green-light: rgba(255, 255, 255, 0.25);
4648
--dark-text: rgba(0, 0, 0, 0.7);
4749
--light-gray: #f5f5f5;
4850
--border-gray: #e0e0e0;
4951
--max-width: 900px;
52+
--sidebar-width: 200px;
5053
--spacing-unit: 1rem;
5154
}
5255

@@ -116,18 +119,99 @@ body {
116119
}
117120

118121
.cv-download-bar .download-btn:hover {
119-
background-color: var(--bg-green);
122+
background-color: var(--hover-green-light);
120123
color: white;
121124
transform: translateY(-2px);
122125
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
123126
}
124127

128+
/* Sidebar Navigation
129+
========================================================================== */
130+
131+
.cv-sidebar {
132+
position: fixed;
133+
top: 92px;
134+
left: 20px;
135+
width: var(--sidebar-width);
136+
max-height: calc(100vh - 110px);
137+
overflow-y: auto;
138+
background-color: white;
139+
border: 1px solid var(--border-gray);
140+
border-radius: 4px;
141+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
142+
padding: 1rem 0;
143+
z-index: 100;
144+
}
145+
146+
.cv-sidebar-title {
147+
font-size: 0.9rem;
148+
font-weight: bold;
149+
color: var(--primary-green);
150+
padding: 0 1rem 0.5rem 1rem;
151+
margin-bottom: 0.5rem;
152+
border-bottom: 1px solid var(--border-gray);
153+
letter-spacing: 0.5px;
154+
}
155+
156+
.cv-sidebar nav {
157+
display: flex;
158+
flex-direction: column;
159+
}
160+
161+
.cv-sidebar nav a {
162+
font-size: 0.85rem;
163+
color: var(--dark-text);
164+
text-decoration: none;
165+
padding: 0.4rem 1rem;
166+
border-left: 3px solid transparent;
167+
transition: all 0.2s ease;
168+
line-height: 1.3;
169+
}
170+
171+
.cv-sidebar nav a:hover {
172+
background-color: var(--bg-green-light);
173+
border-left-color: var(--primary-green);
174+
color: var(--primary-green);
175+
text-decoration: none;
176+
}
177+
178+
.cv-sidebar nav a.active {
179+
background-color: var(--bg-green);
180+
border-left-color: var(--primary-green);
181+
color: var(--primary-green);
182+
font-weight: bold;
183+
}
184+
185+
/* Scrollbar styling for sidebar */
186+
.cv-sidebar::-webkit-scrollbar {
187+
width: 4px;
188+
}
189+
190+
.cv-sidebar::-webkit-scrollbar-track {
191+
background: transparent;
192+
}
193+
194+
.cv-sidebar::-webkit-scrollbar-thumb {
195+
background-color: var(--border-gray);
196+
border-radius: 2px;
197+
}
198+
199+
.cv-sidebar::-webkit-scrollbar-thumb:hover {
200+
background-color: var(--primary-green);
201+
}
202+
125203
/* Main Content Container
126204
========================================================================== */
127205

206+
.cv-wrapper {
207+
display: flex;
208+
justify-content: center;
209+
}
210+
128211
.cv-content {
129212
max-width: var(--max-width);
130213
margin: 2rem auto;
214+
margin-left: calc(var(--sidebar-width) + 60px);
131215
padding: 2rem;
132216
background-color: white;
133217
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
@@ -180,6 +264,11 @@ h2 {
180264
letter-spacing: 0;
181265
}
182266

267+
/* Scroll offset for anchor links (accounts for fixed header) */
268+
section[id] {
269+
scroll-margin-top: 80px;
270+
}
271+
183272
h3 {
184273
font-size: 1.05rem;
185274
font-weight: normal;
@@ -372,6 +461,17 @@ strong, b {
372461
/* Responsive Design - Tablet
373462
========================================================================== */
374463

464+
@media screen and (max-width: 1200px) {
465+
.cv-sidebar {
466+
display: none;
467+
}
468+
469+
.cv-content {
470+
margin-left: auto;
471+
margin-right: auto;
472+
}
473+
}
474+
375475
@media screen and (max-width: 768px) {
376476
body {
377477
padding-top: 80px;
@@ -495,13 +595,15 @@ strong, b {
495595
background: white;
496596
}
497597

498-
.cv-download-bar {
598+
.cv-download-bar,
599+
.cv-sidebar {
499600
display: none;
500601
}
501602

502603
.cv-content {
503604
max-width: 100%;
504605
margin: 0;
606+
margin-left: 0;
505607
padding: 0;
506608
box-shadow: none;
507609
}

documents/JRM_CV.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@
1414
</div>
1515
</div>
1616

17+
<aside class="cv-sidebar">
18+
<div class="cv-sidebar-title">Sections</div>
19+
<nav>
20+
<a href="#employment">Employment</a>
21+
<a href="#education">Education</a>
22+
<a href="#grants-honors-and-awards-selected">Grants, honors, and aw...</a>
23+
<a href="#publications">Publications</a>
24+
<a href="#invited-talks-selected">Invited talks (selected)</a>
25+
<a href="#software-selected">Software (selected)</a>
26+
<a href="#teaching-and-instruction">Teaching and instruction</a>
27+
<a href="#service">Service</a>
28+
</nav>
29+
</aside>
30+
1731
<div class="cv-content">
1832
<header class="cv-header">
1933
<h1>Jeremy R. Manning, <span class="small-caps">Ph.D.</span></h1>

documents/JRM_CV.pdf

-3 Bytes
Binary file not shown.

scripts/extract_cv.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,18 @@ def generate_html(tex_content: str) -> str:
537537

538538
html_parts = []
539539

540+
# Build sidebar navigation from sections
541+
sidebar_links = []
542+
for section in sections:
543+
section_id = section.title.lower()
544+
section_id = re.sub(r'[^a-z0-9]+', '-', section_id).strip('-')
545+
# Shorten some section titles for sidebar display
546+
display_title = section.title
547+
if len(display_title) > 25:
548+
# Truncate long titles
549+
display_title = display_title[:22] + '...'
550+
sidebar_links.append(f' <a href="#{section_id}">{display_title}</a>\n')
551+
540552
# HTML header
541553
html_parts.append('''<!DOCTYPE html>
542554
<html lang="en">
@@ -554,6 +566,14 @@ def generate_html(tex_content: str) -> str:
554566
</div>
555567
</div>
556568
569+
<aside class="cv-sidebar">
570+
<div class="cv-sidebar-title">Sections</div>
571+
<nav>
572+
''')
573+
html_parts.extend(sidebar_links)
574+
html_parts.append(''' </nav>
575+
</aside>
576+
557577
<div class="cv-content">
558578
''')
559579

0 commit comments

Comments
 (0)