Files
beantownbabeandClaude Sonnet 5 a62208ff9b Trim Conference Scout candidates per travel decisions
Removed PCIM Asia, IMAPS Onshoring Workshop, and SEMICON Taiwan (not
happening) and ICSCRM 2026 (no international travel to Japan).
Flagged WiPDA-Europe (Aalborg) as a real candidate worth raising at
the next meeting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 08:55:47 +02:00

345 lines
17 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ---------- Opportunities calendar ----------
Each entry: { start: "YYYY-MM-DD", end: "YYYY-MM-DD" (defaults to start),
title, location, attendee (optional) }.
Multi-day entries render as one bar spanning their full date range;
bars continuing past a week boundary lose the rounded corner on that side. */
var OPPORTUNITIES = [
{ start: "2026-08-23", end: "2026-08-27", title: "SPIE", location: "San Diego, CA", attendee: "Peter", url: "https://spie.org/conferences-and-exhibitions/optics-and-photonics",
abstract: "SPIE's flagship annual optics and photonics conference and exhibition, held every August in San Diego since the 1960s. Brings together 10,000+ scientists, engineers, and industry professionals across optical engineering, nanoscience, quantum science, and organic photonics." },
{ start: "2026-11-10", end: "2026-11-13", title: "SEMICON Europa", location: "Munich, Germany", url: "https://www.semiconeuropa.org/",
abstract: "Semiconductor and electronics manufacturing trade show co-located with electronica in Munich. Covers fab management, advanced packaging, and smart manufacturing across the chip supply chain, drawing 8,000+ visitors from equipment vendors, fabs, and OSATs." },
{ start: "2026-09-01", title: "NCN Mix & Match", location: "DESY Campus, Hamburg, Germany", url: "https://northernchipnetwork.de/veranstaltungen/event",
abstract: "Northern Chip Network's first networking event for microelectronics professionals in Northern Germany, held on TXproducts' home DESY campus (1pm-6pm). Lightning-pitch format for presenting projects/research; open to members and prospective members." },
{ start: "2026-09-08", end: "2026-09-10", title: "SNIB2026", location: "University of Hamburg, Germany", attendee: "Peter Gaal, Daniel Schmidt", url: "https://www.sni-portal.de/en/sni-conferences/snib2026",
abstract: "German Conference on Research with Synchrotron Radiation, Neutrons, Ions and Accelerators at Large-Scale Facilities — brings together researchers, industry leaders, and policymakers, with a focus on AI, digitalisation, sustainability, and technology transfer. Hosted by DESY, European XFEL, and University of Hamburg." }
];
var MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var MONTH_ABBR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var oppCursor = new Date();
oppCursor.setDate(1);
function oppKey(d) {
return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
}
function parseOppDate(s) {
var parts = s.split("-").map(Number);
return new Date(parts[0], parts[1] - 1, parts[2]);
}
function addOppDays(d, n) {
var r = new Date(d);
r.setDate(r.getDate() + n);
return r;
}
function buildOppEvents() {
return OPPORTUNITIES.map(function (o) {
return {
title: o.title, location: o.location, attendee: o.attendee, url: o.url, abstract: o.abstract,
start: parseOppDate(o.start), end: parseOppDate(o.end || o.start)
};
}).sort(function (a, b) { return a.start - b.start; });
}
function formatOppDateRange(start, end) {
if (start.getTime() === end.getTime()) {
return MONTH_ABBR[start.getMonth()] + " " + start.getDate() + ", " + start.getFullYear();
}
if (start.getFullYear() === end.getFullYear()) {
if (start.getMonth() === end.getMonth()) {
return MONTH_ABBR[start.getMonth()] + " " + start.getDate() + "–" + end.getDate() + ", " + start.getFullYear();
}
return MONTH_ABBR[start.getMonth()] + " " + start.getDate() + " – " + MONTH_ABBR[end.getMonth()] + " " + end.getDate() + ", " + start.getFullYear();
}
return MONTH_ABBR[start.getMonth()] + " " + start.getDate() + ", " + start.getFullYear() + " – " + MONTH_ABBR[end.getMonth()] + " " + end.getDate() + ", " + end.getFullYear();
}
function renderOppEventList() {
var listEl = document.getElementById("opp-event-list");
if (!listEl) return;
listEl.innerHTML = "";
var events = buildOppEvents();
if (!events.length) {
var empty = document.createElement("div");
empty.className = "opp-list-empty";
empty.textContent = "No events yet.";
listEl.appendChild(empty);
return;
}
events.forEach(function (e) {
var row = document.createElement("div");
row.className = "opp-list-row";
var meta = document.createElement("div");
meta.className = "opp-list-meta";
var datesEl = document.createElement("div");
datesEl.className = "opp-list-dates";
datesEl.textContent = formatOppDateRange(e.start, e.end);
meta.appendChild(datesEl);
if (e.location) {
var locEl = document.createElement("div");
locEl.className = "opp-list-loc";
locEl.textContent = e.location;
meta.appendChild(locEl);
}
if (e.attendee) {
var attEl = document.createElement("div");
attEl.className = "opp-list-attendee";
attEl.textContent = "Attending: " + e.attendee;
meta.appendChild(attEl);
}
if (e.url) {
var linkEl = document.createElement("a");
linkEl.className = "opp-list-link";
linkEl.href = e.url;
linkEl.target = "_blank";
linkEl.rel = "noopener";
linkEl.textContent = "Website";
meta.appendChild(linkEl);
}
row.appendChild(meta);
var about = document.createElement("div");
about.className = "opp-list-about";
var badge = document.createElement(e.url ? "a" : "span");
badge.className = "opp-list-badge";
badge.textContent = e.title;
if (e.url) {
badge.href = e.url;
badge.target = "_blank";
badge.rel = "noopener";
}
about.appendChild(badge);
if (e.abstract) {
var abstractEl = document.createElement("p");
abstractEl.className = "opp-list-abstract";
abstractEl.textContent = e.abstract;
about.appendChild(abstractEl);
}
row.appendChild(about);
row.addEventListener("click", function () {
oppCursor = new Date(e.start.getFullYear(), e.start.getMonth(), 1);
renderOppCalendar();
});
listEl.appendChild(row);
});
}
function renderOppCalendar() {
var label = document.getElementById("opp-month-label");
var grid = document.getElementById("opp-cal-grid");
if (!label || !grid) return;
label.textContent = MONTH_NAMES[oppCursor.getMonth()] + " " + oppCursor.getFullYear();
grid.innerHTML = "";
var weekdayRow = document.createElement("div");
weekdayRow.className = "opp-cal-weekdays";
["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].forEach(function (wd) {
var wdEl = document.createElement("div");
wdEl.className = "opp-cal-weekday";
wdEl.textContent = wd;
weekdayRow.appendChild(wdEl);
});
grid.appendChild(weekdayRow);
var year = oppCursor.getFullYear(), month = oppCursor.getMonth();
var firstDow = new Date(year, month, 1).getDay();
var daysInMonth = new Date(year, month + 1, 0).getDate();
var totalCells = Math.ceil((firstDow + daysInMonth) / 7) * 7;
var gridStart = new Date(year, month, 1 - firstDow);
var todayKey = oppKey(new Date());
var events = buildOppEvents();
for (var w = 0; w < totalCells / 7; w++) {
var weekStart = addOppDays(gridStart, w * 7);
var weekEnd = addOppDays(weekStart, 6);
var weekEl = document.createElement("div");
weekEl.className = "opp-cal-week";
var weekEvents = events
.filter(function (e) { return e.start <= weekEnd && e.end >= weekStart; })
.sort(function (a, b) { return a.start - b.start; });
var lanes = [];
weekEvents.forEach(function (e) {
var colStart = Math.max(0, Math.round((Math.max(e.start, weekStart) - weekStart) / 86400000));
var colEnd = Math.min(6, Math.round((Math.min(e.end, weekEnd) - weekStart) / 86400000));
var lane = 0;
while (lanes[lane] && lanes[lane].some(function (r) { return !(colEnd < r[0] || colStart > r[1]); })) lane++;
if (!lanes[lane]) lanes[lane] = [];
lanes[lane].push([colStart, colEnd]);
e._col = [colStart, colEnd];
e._lane = lane;
});
var cellMinHeight = Math.max(96, 34 + lanes.length * 24 + 10);
for (var d = 0; d < 7; d++) {
var cellDate = addOppDays(weekStart, d);
var outside = cellDate.getMonth() !== month;
var key = oppKey(cellDate);
var cell = document.createElement("div");
cell.className = "opp-cal-cell" + (outside ? " outside" : "") + (key === todayKey ? " today" : "");
cell.style.minHeight = cellMinHeight + "px";
var numEl = document.createElement("div");
numEl.className = "opp-cal-daynum";
numEl.textContent = cellDate.getDate();
cell.appendChild(numEl);
weekEl.appendChild(cell);
}
weekEvents.forEach(function (e) {
var bar = document.createElement("div");
bar.className = "opp-cal-event-bar";
if (e.start < weekStart) bar.classList.add("continues-left");
if (e.end > weekEnd) bar.classList.add("continues-right");
bar.style.left = "calc(" + (e._col[0] / 7 * 100) + "% + 4px)";
bar.style.width = "calc(" + ((e._col[1] - e._col[0] + 1) / 7 * 100) + "% - 8px)";
bar.style.top = (34 + e._lane * 24) + "px";
var titleEl = document.createElement(e.url ? "a" : "span");
titleEl.className = "opp-cal-event-title";
titleEl.textContent = e.title;
if (e.url) {
titleEl.href = e.url;
titleEl.target = "_blank";
titleEl.rel = "noopener";
}
bar.appendChild(titleEl);
if (e.location) {
var locEl = document.createElement("span");
locEl.className = "opp-cal-event-loc";
locEl.textContent = e.location;
bar.appendChild(locEl);
}
bar.title = e.title + (e.location ? " — " + e.location : "") + (e.attendee ? " (" + e.attendee + ")" : "");
weekEl.appendChild(bar);
});
grid.appendChild(weekEl);
}
}
/* ---------- Conference Scout results ----------
Snapshot of the weekly research agent's report, hand-reviewed and pasted in here.
Each entry: { title, dates (display text), location, url, reason }. */
var SCOUT_RESULTS = [
{ title: "WiPDA-Europe 2026", dates: "Sept 20–22, 2026", location: "Aalborg, Denmark",
url: "https://www.energy.aau.dk/wipda-europe-2026-e156452",
reason: "IEEE workshop on wide-bandgap (GaN/SiC) power devices — niche but highly targeted technical audience. Existing focus area. Flagged as a real candidate — worth raising at the meeting." },
{ title: "XTOP 2026", dates: "Sept 21–25, 2026", location: "Karlsruhe, Germany",
url: "https://xtop2026.kit.edu",
reason: "16th Biennial Conference on High-Resolution X-Ray Diffraction and Imaging — direct X-ray diffraction/imaging overlap. Existing focus area." },
{ title: "NOBUGS 2026", dates: "Sept 21–25, 2026 (core Sept 22–24)", location: "Schenefeld Campus (European XFEL), near Hamburg, Germany",
url: "https://nobugs2026.xfel.eu/",
reason: "Explicitly covers metadata/data formats and FAIR data management for beamline software; co-hosted by DESY/European XFEL on TXproducts' home campus — the single best topical fit found. Existing focus area." },
{ title: "RDA 27th Plenary Meeting (P27)", dates: "Oct 6–8, 2026", location: "London, UK",
url: "https://www.rd-alliance.org/plenaries/p27/",
reason: "Research Data Alliance plenary — strong FAIR/research-data-infrastructure networking, though less domain-specific than NOBUGS. Existing focus area." },
{ title: "AFLS2026", dates: "Nov 16–20, 2026", location: "Harare, Zimbabwe",
url: "https://events.saip.org.za/event/255",
reason: "African Light Source / African Physical Society joint meeting — the Africa-based synchrotron-development community, with materials/X-ray characterization topics. Existing focus area." },
{ title: "MRS Fall Meeting & Exhibit 2026", dates: "Nov 29–Dec 4, 2026", location: "Boston, MA, USA",
url: "https://www.mrs.org/",
reason: "Broad materials-science conference with strong X-ray characterization tracks. Existing focus area." },
{ title: "GOMACTech 2027", dates: "March 22–25, 2027", location: "Pasadena, CA, USA",
url: "https://www.gomactech.net/",
reason: "The premier US DoD microelectronics conference — covers GaN/SiC power devices and X-ray characterization/reliability for defense microelectronics. Potential new business (defense)." },
{ title: "IEEE RadarConf'27", dates: "May 1–6, 2027", location: "Bangalore, India",
url: "https://radarconf2027.org/",
reason: "Radar hardware relies heavily on GaN/SiC RF power amplifiers — a defense-radar audience in a growing Indian defense-electronics market. Potential new business (defense)." }
];
function renderOppScoutList() {
var listEl = document.getElementById("opp-scout-list");
if (!listEl) return;
listEl.innerHTML = "";
if (!SCOUT_RESULTS.length) {
var empty = document.createElement("div");
empty.className = "opp-list-empty";
empty.textContent = "No results yet.";
listEl.appendChild(empty);
return;
}
SCOUT_RESULTS.forEach(function (s) {
var row = document.createElement("div");
row.className = "opp-list-row";
row.style.cursor = "default";
var meta = document.createElement("div");
meta.className = "opp-list-meta";
var datesEl = document.createElement("div");
datesEl.className = "opp-list-dates";
datesEl.textContent = s.dates;
meta.appendChild(datesEl);
if (s.location) {
var locEl = document.createElement("div");
locEl.className = "opp-list-loc";
locEl.textContent = s.location;
meta.appendChild(locEl);
}
if (s.url) {
var linkEl = document.createElement("a");
linkEl.className = "opp-list-link";
linkEl.href = s.url;
linkEl.target = "_blank";
linkEl.rel = "noopener";
linkEl.textContent = "Website";
meta.appendChild(linkEl);
}
row.appendChild(meta);
var about = document.createElement("div");
about.className = "opp-list-about";
var badge = document.createElement(s.url ? "a" : "span");
badge.className = "opp-list-badge";
badge.textContent = s.title;
if (s.url) {
badge.href = s.url;
badge.target = "_blank";
badge.rel = "noopener";
}
about.appendChild(badge);
if (s.reason) {
var reasonEl = document.createElement("p");
reasonEl.className = "opp-list-abstract";
reasonEl.textContent = s.reason;
about.appendChild(reasonEl);
}
row.appendChild(about);
listEl.appendChild(row);
});
}
document.getElementById("opp-prev-btn").addEventListener("click", function () {
oppCursor.setMonth(oppCursor.getMonth() - 1);
renderOppCalendar();
});
document.getElementById("opp-next-btn").addEventListener("click", function () {
oppCursor.setMonth(oppCursor.getMonth() + 1);
renderOppCalendar();
});
document.getElementById("opp-today-btn").addEventListener("click", function () {
oppCursor = new Date();
oppCursor.setDate(1);
renderOppCalendar();
});
renderOppEventList();
renderOppCalendar();
renderOppScoutList();
/* ---------- Module self-registration ----------
Everything below wires this module into the shared shell (app.js):
the drill-view registry, the hero-nav button, and the tab's default view.
This runs once, right after opportunities.html is injected into the DOM. */
HERO_NAV_BY_TAB.opportunities = ["hero-nav-scout"];
DRILL_DEFAULT_VIEW.opportunities = "opportunities-root";
DRILL_CONFIG.opportunities = {
crumbsEl: "opp-crumbs",
crumbs: {
"opportunities-root": [["Opportunities", "opportunities-root"]],
"scout": [["Opportunities", "opportunities-root"], ["Conference Scout", "scout"]]
}
};
document.querySelectorAll("#tab-opportunities .drill-back, #tab-opportunities .drill-next").forEach(function (b) {
b.addEventListener("click", function () { setDrillView("opportunities", b.getAttribute("data-target")); });
});
setDrillView("opportunities", DRILL_DEFAULT_VIEW.opportunities);
document.getElementById("hero-nav-scout-btn").addEventListener("click", function () {
setDrillView("opportunities", "scout");
});
if (document.querySelector(".sidebar-nav-btn.active[data-tab=\"opportunities\"]")) {
document.getElementById("hero-nav-scout").style.display = "flex";
}