Skip to content

Commit 5d8890f

Browse files
committed
deploy: 1a94e18
1 parent 980b341 commit 5d8890f

File tree

4 files changed

+658
-32
lines changed

4 files changed

+658
-32
lines changed

about/team.html

Lines changed: 229 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,220 @@
8080
</div>
8181
</div>
8282

83-
<figure class="image-caption">
84-
<img class="figure-img img-fluid" src="/assets/images/250114 - Org Chart-2.png" alt="US CMS S&amp;C Org Chart" />
85-
<figcaption></figcaption>
86-
</figure>
83+
<html lang="en">
84+
<head>
85+
<meta charset="UTF-8" />
86+
<title>USCMS S&amp;C Org Chart (Auto-Generated)</title>
87+
<style>
88+
body { background:#fff; font-family:sans-serif; }
89+
.chart-container { position:relative; width:1200px; height:800px; margin:auto;}
90+
91+
.node { position:absolute; text-align:center; }
92+
.node.root { width:300px; }
93+
.node.leaf { width:200px; }
94+
95+
.node-box {
96+
border:2px solid #000; padding:10px; background:#fff;
97+
font-size:14px; font-weight:normal; line-height:1.4; text-align:left;
98+
box-shadow:2px 2px 5px rgba(0,0,0,0.1);
99+
}
100+
.node-box strong { display:block; text-align:center; font-size:15px; margin-bottom:6px; }
101+
.person-line { font-size:12px; }
102+
.title-line { font-size:11px; font-style:italic; color:#555; margin-left:2px; }
103+
104+
.photo-left,.photo-right,.photo-below{
105+
position:absolute; width:75px; height:75px; object-fit:cover;
106+
}
107+
.photo-left{ left:-85px; top:50%; transform:translateY(-50%); }
108+
.photo-right{ right:-85px; top:50%; transform:translateY(-50%); }
109+
.photo-below{ top:100%; margin-top:8px; }
110+
canvas { position:absolute; top:0; left:0; z-index:0; }
111+
</style>
112+
</head>
113+
<body>
114+
<div id="chart" class="chart-container">
115+
<canvas id="connectorCanvas" width="1200" height="800"></canvas>
116+
</div>
117+
118+
119+
120+
121+
122+
123+
124+
<script>
125+
/* Parse Liquid-generated JSON */
126+
const layoutMap = JSON.parse("{ \"management\": [ { \"name\": \"Tulika Bose\", \"shortname\": \"tulika176\", \"title\": \"S&C Operations Program Manager\", \"institution\": \"University of Wisconsin-Madison\", \"photo\": \"/assets/images/team/Tulika_Bose.jpg\" }, { \"name\": \"Dirk Hufnagel\", \"shortname\": \"d_hufnagel\", \"title\": \"Deputy S&C Operations Program Manager\\n\", \"institution\": \"Fermilab\", \"photo\": \"/assets/images/team/Dirk-Hufnagel.jpg\" }, { \"name\": \"Robert Tuck\", \"shortname\": \"rct225\", \"title\": \"Associate Project Manager\", \"institution\": \"Princeton University\", \"photo\": \"/assets/images/team/Robert-Tuck.jpg\" } ] , \"facilities\": [ { \"name\": \"Andrew Melo\", \"shortname\": \"PerilousApricot\", \"title\": \"Facilities Co-Leader\", \"institution\": \"Vanderbilt University\", \"photo\": \"/assets/images/team/Andrew_Melo.jpg\" }, { \"name\": \"David Mason\", \"shortname\": \"d_mason\", \"title\": \"Facilities Co-Leader\", \"institution\": \"Fermilab\", \"photo\": \"/assets/images/team/David_Mason.jpg\" } ] , \"software\": [ { \"name\": \"Saba Sehrish\", \"shortname\": \"ssehrish\", \"title\": \"Software Co-leader\", \"institution\": \"Fermilab\", \"photo\": \"/assets/images/team/Saba_Sehrish.jpg\" }, { \"name\": \"Kevin Lannon\", \"shortname\": \"klannon\", \"title\": \"Software Co-leader\", \"institution\": \"University of Notre Dame\", \"photo\": \"/assets/images/team/Kevin_Lannon.jpeg\" } ] , \"operations\": [ { \"name\": \"Duong Nguyen\", \"shortname\": \"nhduongvn\", \"title\": \"Operations Co-Leader\", \"institution\": \"University at Buffalo\", \"photo\": \"/assets/images/team/Duong_Nguyen.jpg\" }, { \"name\": \"Scarlet Norberg\", \"shortname\": \"s_norberg\", \"title\": \"Operations Co-Leader\\n\", \"institution\": \"Fermilab\", \"photo\": \"/assets/images/team/Scarlet-Norberg.png\" } ] , \"hllhc\": [ { \"name\": \"Lindsey Gray\", \"shortname\": \"l_gray\", \"title\": \"HL-LHC R&D Co-Leader\", \"institution\": \"Fermilab\", \"photo\": \"/assets/images/team/Lindsey-Gray.png\" } , { \"name\": \"David Sperka\", \"shortname\": \"dsperka\", \"title\": \"HL-LHC R&D Co-Leader\", \"institution\": \"Boston University\", \"photo\": \"/assets/images/team/David_Sperka.jpg\" } ], \"analysis\": [ { \"name\": \"Matteo Cremonesi\", \"shortname\": \"mcremone\", \"title\": \"HL-LHC R&D Analysis Systems Coordinator\", \"institution\": \"Carnegie Mellon University\", \"photo\": \"/assets/images/team/Matteo_Cremonesi.jpg\" } , { \"name\": \"Oksana Shadura\", \"shortname\": \"oshadura\", \"title\": \"HL-LHC R&D Analysis Systems Coordinator\", \"institution\": \"University of Nebraska - Lincoln\", \"photo\": \"/assets/images/team/Oksana-Shadura_.jpg\" } ], \"infra\": [ { \"name\": \"Nick Smith\", \"shortname\": \"nsmith-\", \"title\": \"U.S. CMS Fermilab Facility Architect\", \"institution\": \"Fermilab\", \"photo\": \"/assets/images/team/Nick_Smith.jpg\" } , { \"name\": \"James Letts\", \"shortname\": \"j_letts\", \"title\": \"U.S. CMS University Facility Architect\", \"institution\": \"UC San Diego\", \"photo\": \"/assets/images/team/James_Letts.jpg\" } ], \"algo\": [ { \"name\": \"Philip Chang\", \"shortname\": \"pchang\", \"title\": \"HL-LHC R&D Algorithms Coordinator\", \"institution\": \"University of Florida\", \"photo\": \"/assets/images/team/Philip_Chang.png\" } ], \"blueprint\": [ { \"name\": \"David Lange\", \"shortname\": \"dlange\", \"title\": \"Computational Physicist\", \"institution\": \"Princeton University\", \"photo\": \"/assets/images/team/David-Lange.png\" } ]}");
127+
const titles = JSON.parse("{ \"management\": \"Software & Computing\", \"facilities\": \"Facilities\", \"software\": \"Software\", \"operations\": \"Operations\", \"hllhc\": \"HL-LHC R&D\", \"analysis\": \"Analysis\", \"infra\": \"Infrastructure\", \"algo\": \"Algorithms\", \"blueprint\": \"Blueprint\"}");
128+
const instShortByPerson = JSON.parse("{ }");
129+
130+
/* Positions: Blueprint intentionally excluded */
131+
const positions = {
132+
management: {left:450, top:40, title:"Software & Computing", type:"root"},
133+
facilities: {left:300, top:220, title:"Facilities", type:"leaf"},
134+
software: {left:300, top:360, title:"Software", type:"leaf"},
135+
operations: {left:600, top:220, title:"Operations", type:"leaf"},
136+
hllhc: {left:600, top:360, title:"HL-LHC R&D", type:"leaf"},
137+
infra: {left:360, top:500, title:"Infrastructure", type:"leaf"},
138+
algo: {left:470, top:500, title:"Algorithms", type:"leaf"},
139+
analysis: {left:580, top:500, title:"Analysis", type:"leaf"}
140+
141+
/*
142+
Example: If you ever want to show Blueprint (currently invisible),
143+
just uncomment and adjust coordinates like so:
144+
145+
blueprint: {left:900, top:500, title:"Blueprint", type:"leaf"}
146+
*/
147+
};
148+
149+
/* Overlay YAML titles */
150+
Object.keys(positions).forEach(k => {
151+
if (titles[k]) positions[k].title = titles[k];
152+
});
153+
154+
/* Titles to always display */
155+
const showTitleForShort = new Set(["tulika176","d_hufnagel","rct225","j_letts","nsmith-"]);
156+
157+
const chart = document.getElementById('chart');
158+
159+
/* Photo helpers */
160+
function addPhotos(key, div, names){
161+
if (["facilities","software"].includes(key)) {
162+
names.forEach((p,i)=>{
163+
const img = document.createElement('img');
164+
img.className = 'photo-left';
165+
if (i === 1) img.style.left = '-170px';
166+
if (p.photo) img.src = p.photo;
167+
img.alt = p.name;
168+
div.appendChild(img);
169+
});
170+
} else if (["operations","hllhc"].includes(key)) {
171+
names.forEach((p,i)=>{
172+
const img = document.createElement('img');
173+
img.className = 'photo-right';
174+
if (i === 1) img.style.right = '-170px';
175+
if (p.photo) img.src = p.photo;
176+
img.alt = p.name;
177+
div.appendChild(img);
178+
});
179+
} else if (key === "management") {
180+
names.forEach((p,i)=>{
181+
const img = document.createElement('img');
182+
img.className = i === 0 ? 'photo-left' : 'photo-right';
183+
if (i === 1) img.style.right = '-85px';
184+
if (i === 2) img.style.right = '-170px';
185+
if (p.photo) img.src = p.photo;
186+
img.alt = p.name;
187+
div.appendChild(img);
188+
});
189+
} else if (["infra","algo","analysis"].includes(key)) {
190+
const imgSize = 75;
191+
const gap = 8;
192+
const count = names.length;
193+
const groupWidth = count * imgSize + Math.max(0, count - 1) * gap;
194+
const nodeW = div.offsetWidth;
195+
const startX = Math.max(0, Math.round((nodeW - groupWidth) / 2));
196+
names.forEach((p,i)=>{
197+
const img = document.createElement('img');
198+
img.className = 'photo-below';
199+
img.style.left = `${startX + i * (imgSize + gap)}px`;
200+
if (p.photo) img.src = p.photo;
201+
img.alt = p.name;
202+
div.appendChild(img);
203+
});
204+
}
205+
}
206+
207+
/* Render a node */
208+
function mkNode(key){
209+
const {left, top, title, type} = positions[key];
210+
const div = document.createElement('div');
211+
div.className = `node ${type}`;
212+
div.style.left = `${left}px`;
213+
div.style.top = `${top}px`;
214+
215+
const box = document.createElement('div');
216+
box.className = 'node-box';
217+
218+
const strong = document.createElement('strong');
219+
strong.textContent = title;
220+
box.appendChild(strong);
221+
222+
const names = (layoutMap[key]||[]).filter(Boolean);
223+
224+
names.forEach(p => {
225+
const instShort = instShortByPerson[p.shortname] || p.institution || "";
226+
const nameLine = document.createElement('div');
227+
nameLine.className = 'person-line';
228+
nameLine.textContent = instShort ? `${p.name} (${instShort})` : p.name;
229+
box.appendChild(nameLine);
230+
231+
if (showTitleForShort.has(p.shortname) && p.title) {
232+
const t = document.createElement('div');
233+
t.className = 'title-line';
234+
t.textContent = p.title;
235+
box.appendChild(t);
236+
}
237+
});
238+
239+
div.appendChild(box);
240+
chart.appendChild(div);
241+
addPhotos(key, div, names);
242+
243+
return div;
244+
}
245+
246+
/* Build nodes */
247+
const nodes = {};
248+
Object.keys(positions).forEach(k => { nodes[k]=mkNode(k); });
249+
250+
/* Connectors */
251+
const canvas = document.getElementById('connectorCanvas');
252+
const ctx = canvas.getContext('2d');
253+
ctx.lineWidth = 2; ctx.strokeStyle = '#000';
254+
255+
function rect(el){ const r = el.getBoundingClientRect(), p = canvas.getBoundingClientRect(); return {
256+
left:r.left-p.left, right:r.right-p.left, top:r.top-p.top, bottom:r.bottom-p.top, width:r.width, height:r.height
257+
};}
258+
function center(el){ const r=rect(el); return {x:r.left+r.width/2,y:r.top+r.height/2};}
259+
function topCenter(el){ const r=rect(el); return {x:r.left+r.width/2,y:r.top};}
260+
function bottomCenter(el){ const r=rect(el); return {x:r.left+r.width/2,y:r.bottom};}
261+
function line(x1,y1,x2,y2){ ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); }
262+
function setLeftByCenter(nodeEl, targetCenterX){
263+
const r = rect(nodeEl);
264+
nodeEl.style.left = `${Math.round(targetCenterX - r.width/2)}px`;
265+
}
266+
267+
window.onload = () => {
268+
const {management, facilities, software, operations, hllhc, infra, algo, analysis} = nodes;
269+
270+
const trunkX = (center(facilities).x + center(operations).x) / 2;
271+
setLeftByCenter(management, trunkX);
272+
273+
const hCenter = center(hllhc).x;
274+
const smallGap = 220;
275+
const centers = [hCenter - smallGap, hCenter, hCenter + smallGap];
276+
[infra, algo, analysis].forEach((el, i) => setLeftByCenter(el, centers[i]));
277+
278+
ctx.clearRect(0,0,canvas.width,canvas.height);
279+
280+
const yConnector = center(software).y;
281+
line(bottomCenter(management).x, bottomCenter(management).y, bottomCenter(management).x, yConnector);
282+
283+
line(center(facilities).x, center(facilities).y, center(operations).x, center(operations).y);
284+
line(center(software).x, center(software).y, center(hllhc).x, center(hllhc).y);
285+
286+
const barY = topCenter(infra).y - 20;
287+
line(center(hllhc).x, bottomCenter(hllhc).y, center(hllhc).x, barY);
288+
289+
[infra, algo, analysis].forEach(node=>{
290+
line(center(hllhc).x, barY, center(node).x, barY);
291+
line(center(node).x, barY, topCenter(node).x, topCenter(node).y);
292+
});
293+
};
294+
</script>
295+
</body>
296+
</html>
87297

88298
<h1>Full Team</h1>
89299
<p><br /></p>
@@ -124,6 +334,21 @@ <h1>Full Team</h1>
124334
</div>
125335

126336

337+
<div class="card" style="width: 12rem;">
338+
<img class="card-img-top" src="/assets/images/team/Robert-Tuck.jpg" alt="Card image cap" />
339+
<div class="card-body d-flex flex-column">
340+
<div class="card-text">
341+
342+
<b>Robert Tuck</b><br />
343+
344+
<small>Princeton University</small><br /><br />
345+
</div>
346+
<div class="card-text mt-auto"><i><p>Associate Project Manager</p>
347+
</i><br /></div>
348+
</div>
349+
</div>
350+
351+
127352

128353

129354

@@ -351,25 +576,6 @@ <h1>Full Team</h1>
351576

352577

353578

354-
355-
356-
357-
<div class="card" style="width: 12rem;">
358-
<img class="card-img-top" src="/assets/images/team/Robert-Tuck.jpg" alt="Card image cap" />
359-
<div class="card-body d-flex flex-column">
360-
<div class="card-text">
361-
362-
<b>Robert Tuck</b><br />
363-
364-
<small>Princeton University</small><br /><br />
365-
</div>
366-
<div class="card-text mt-auto"><i><p>Associate Project Manager</p>
367-
</i><br /></div>
368-
</div>
369-
</div>
370-
371-
372-
373579
</div>
374580
</div>
375581

0 commit comments

Comments
 (0)