Skip to content

Commit 9893674

Browse files
jeremymanningclaude
andcommitted
Fix CSS width inheritance and add personnel list formatting
- Remove compound 55% width inheritance that was causing sections to be too narrow (55% of 55% = ~30%) - Apply 55% width only at article > direct children level - Add formatPersonnelLists() function to wrap text nodes in spans for CSS grid to work with personnel names in two-column layout - Update definition list selectors to only apply width at top level Fixes: authorship guidelines, getting started, attendance policy, travel policy, making a poster, poster printing, subject compensation, and lab members personnel list formatting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 8941e66 commit 9893674

File tree

2 files changed

+112
-33
lines changed

2 files changed

+112
-33
lines changed

checklist.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ document.addEventListener('DOMContentLoaded', function() {
66
// Wrap orphaned text nodes after h2 headings in containers for proper styling
77
wrapOrphanedTextNodes();
88

9+
// Format personnel lists into two-column grid layout
10+
formatPersonnelLists();
11+
912
// Convert the checklist section to interactive form
1013
// Need to wait a bit for MathJax to potentially process, but also handle native MathML
1114
setTimeout(convertChecklistToInteractive, 100);
@@ -84,6 +87,90 @@ function fixEnumerationNumbering() {
8487
});
8588
}
8689

90+
// Format personnel lists (lab members) into two-column grid layout
91+
// tex4ht generates text nodes directly in divs, but CSS grid needs child elements
92+
function formatPersonnelLists() {
93+
// Find the lab members heading
94+
var labMembersHeading = null;
95+
var h2s = document.querySelectorAll('h2');
96+
h2s.forEach(function(h2) {
97+
if (h2.textContent.toLowerCase().includes('lab members')) {
98+
labMembersHeading = h2;
99+
}
100+
});
101+
102+
if (!labMembersHeading) return;
103+
104+
// Find all h3 elements after the lab members heading (subsections like "Graduate students")
105+
var sibling = labMembersHeading.nextElementSibling;
106+
while (sibling) {
107+
// Stop if we hit another h2 (new major section)
108+
if (sibling.tagName === 'H2') break;
109+
110+
if (sibling.tagName === 'H3') {
111+
// Find the content after this h3 that contains personnel names
112+
var contentSibling = sibling.nextSibling;
113+
var names = [];
114+
115+
// Collect text nodes until we hit another heading or structural element
116+
while (contentSibling) {
117+
if (contentSibling.nodeType === Node.ELEMENT_NODE) {
118+
var tag = contentSibling.tagName;
119+
if (tag === 'H2' || tag === 'H3' || tag === 'P' || tag === 'DL') break;
120+
}
121+
122+
if (contentSibling.nodeType === Node.TEXT_NODE) {
123+
var text = contentSibling.textContent.trim();
124+
if (text) {
125+
// Split by newlines or common separators
126+
var parts = text.split(/[\n\r]+/).map(function(s) { return s.trim(); }).filter(function(s) { return s.length > 0; });
127+
names = names.concat(parts);
128+
}
129+
}
130+
131+
contentSibling = contentSibling.nextSibling;
132+
}
133+
134+
// If we found names, create a grid container
135+
if (names.length > 1) {
136+
// Create the personnel list container
137+
var container = document.createElement('div');
138+
container.className = 'personnel-list';
139+
140+
// Add each name as a span
141+
names.forEach(function(name) {
142+
var span = document.createElement('span');
143+
span.className = 'personnel-item';
144+
span.textContent = name;
145+
container.appendChild(span);
146+
});
147+
148+
// Remove the old text nodes and insert the new container
149+
var toRemove = [];
150+
contentSibling = sibling.nextSibling;
151+
while (contentSibling) {
152+
if (contentSibling.nodeType === Node.ELEMENT_NODE) {
153+
var tag = contentSibling.tagName;
154+
if (tag === 'H2' || tag === 'H3' || tag === 'P' || tag === 'DL') break;
155+
}
156+
toRemove.push(contentSibling);
157+
contentSibling = contentSibling.nextSibling;
158+
}
159+
160+
// Insert container after h3
161+
sibling.parentNode.insertBefore(container, sibling.nextSibling);
162+
163+
// Remove old nodes
164+
toRemove.forEach(function(node) {
165+
if (node.parentNode) node.parentNode.removeChild(node);
166+
});
167+
}
168+
}
169+
170+
sibling = sibling.nextElementSibling;
171+
}
172+
}
173+
87174
// Convert the static checklist to an interactive form
88175
function convertChecklistToInteractive() {
89176
// Find the checklist section by looking for "Checklist and signature page" heading

lab-manual.css

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,23 @@ article {
2525
position: relative;
2626
}
2727

28-
/* Main content width - 55% for Tufte style, leaving room for sidenotes */
28+
/*
29+
* Tufte-style content width: 55% for main content, leaving room for sidenotes
30+
* IMPORTANT: Apply 55% width ONLY at the top level to avoid compound narrowing
31+
* (55% of 55% = 30%, which is too narrow)
32+
*
33+
* tex4ht generates: article > direct content (p, h2, dl, etc.)
34+
* Content inside these should be 100% of their parent
35+
*/
36+
37+
/* Direct children of article get 55% width */
2938
article > p,
30-
article > section > p,
3139
article > h2,
32-
article > section > h2,
3340
article > h3,
34-
article > section > h3,
3541
article > ul,
3642
article > ol,
3743
article > dl,
38-
section > p,
39-
section > h3,
40-
section > ul,
41-
section > ol,
42-
section > dl,
43-
h2 + p,
44-
h3 + p {
45-
width: 55%;
46-
}
47-
48-
/* Text nodes directly after headings (like IRB intro) need width constraint */
49-
/* This targets text that follows h2 but isn't wrapped in p tags */
50-
article > section {
44+
article > div:not(.fullwidth):not(.marginnote):not(.sidenote) {
5145
width: 55%;
5246
}
5347

@@ -92,24 +86,21 @@ p.noindent img {
9286
}
9387

9488
/* Lab member lists - display in two balanced columns */
95-
/* tex4ht generates div elements with names as text content */
89+
/* tex4ht generates text nodes directly in a div - CSS grid can't work with those.
90+
JavaScript will wrap text nodes in spans so grid can lay them out. */
9691
div.columns-2,
97-
.columns-2 {
92+
.columns-2,
93+
.personnel-list {
9894
width: 55%;
9995
display: grid;
10096
grid-template-columns: 1fr 1fr;
101-
gap: 0.5em 2em;
97+
gap: 0.3em 2em;
10298
line-height: 1.6;
10399
}
104100

105-
/* Generic divs in the lab members section that contain names */
106-
/* These are generated by tex4ht for the columns environment */
107-
section h3 ~ div:not(.columns-2):not(.fullwidth):not(.marginnote):not(.sidenote) {
108-
width: 55%;
109-
display: grid;
110-
grid-template-columns: 1fr 1fr;
111-
gap: 0.5em 2em;
112-
line-height: 1.6;
101+
/* Individual personnel items (wrapped by JavaScript) */
102+
.personnel-item {
103+
display: block;
113104
}
114105

115106
/* Margin notes styling - positioned in right margin */
@@ -140,7 +131,8 @@ label.sidenote-number {
140131
}
141132

142133
/* Definition lists (used for numbered items) */
143-
dl {
134+
/* Only top-level dl gets 55% width; nested dl inherits parent width */
135+
article > dl {
144136
width: 55%;
145137
}
146138

@@ -161,10 +153,10 @@ dd dl {
161153
width: 100%;
162154
}
163155

164-
/* Margin notes inside nested lists need adjusted positioning */
165-
dd .marginnote, dd .sidenote {
166-
margin-right: -110%;
167-
width: 45%;
156+
/* Margin notes inside definition lists need adjusted positioning */
157+
dl .marginnote, dl .sidenote {
158+
margin-right: -80%;
159+
width: 40%;
168160
}
169161

170162
/* Checklist styling - make checkboxes visible */

0 commit comments

Comments
 (0)