diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0ca3cf7..ec3beaa 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -33,6 +33,7 @@ jobs:
bio
company
avatarUrl
+ websiteUrl
socialAccounts(first:10) {
edges {
node {
diff --git a/_quarto.yml b/_quarto.yml
index f827c21..66149a9 100644
--- a/_quarto.yml
+++ b/_quarto.yml
@@ -11,10 +11,10 @@ website:
text: Home
- href: index.qmd#events
text: Events
+ - href: whoWeAre.qmd
+ text: Who We Are
- href: resbaz/resbazTucson2024.qmd
text: ResBaz 2024
- # - href: whoWeAre.qmd
- # text: Who We Are
body-footer: |
::: {.footer}
 \
diff --git a/components/nodeLinkDiagram.ojs b/components/nodeLinkDiagram.ojs
new file mode 100644
index 0000000..b431117
--- /dev/null
+++ b/components/nodeLinkDiagram.ojs
@@ -0,0 +1,237 @@
+function nodeLinkDiagram(nodes, links) {
+ let selectNode,
+ selectedNode = null;
+
+ const height = globalThis.screen.height;
+
+ const personNodeRadius = 25;
+ const personNodePaddedRadius = personNodeRadius + 15;
+
+ const highlightOutlineRadius = 5;
+ const highlightStrokeWeight = 5;
+
+ const teamNodeRadius = 75;
+
+ const strokeWeight = 3;
+
+ const gravityMultiplier = 0.3;
+ const maxGravityAlpha = 0.0005;
+ const bounceStrength = 2;
+ const chargeStrength = -2000; // -10 * (personNodeRadius + teamNodeRadius);
+
+ const teamColors = d3.scaleOrdinal(
+ ["WEEKLY", "FESTIVAL"],
+ ["#ea5a2a", "#1e58ac"]
+ );
+
+ const simulation = d3
+ .forceSimulation(nodes)
+ .force(
+ "link",
+ d3.forceLink(links).id((d) => d.id)
+ )
+ .force("charge", d3.forceManyBody().strength(chargeStrength))
+ .force("centerAndBounds", (alpha) => {
+ nodes.forEach((d) => {
+ const radius =
+ d.type === "PERSON" ? personNodePaddedRadius : teamNodeRadius;
+ // Kinda weird, but has a nice effect: apply gravity more strongly
+ // (within a limit) at the beginning of a layout / while you're
+ // dragging, but taper it off toward the end
+ const gravityAlpha = Math.min(
+ (alpha * gravityMultiplier) ** 2,
+ maxGravityAlpha
+ );
+
+ if (d.x < radius) {
+ d.x = radius;
+ d.vx += alpha * bounceStrength * (radius - d.x);
+ } else if (d.x > width - radius) {
+ d.x = width - radius;
+ d.vx += -alpha * bounceStrength * (d.x - width - radius);
+ }
+ const dx = width / 2 - d.x;
+ d.vx += Math.sign(dx) * gravityAlpha * dx ** 2;
+
+ if (d.y < radius) {
+ d.y = radius;
+ d.vy += alpha * bounceStrength * (radius - d.y);
+ } else if (d.y > height - radius) {
+ d.y = height - radius;
+ d.vy += -alpha * bounceStrength * (d.y - height - radius);
+ }
+ const dy = height / 2 - d.y;
+ d.vy += Math.sign(dy) * gravityAlpha * dy ** 2;
+ });
+ })
+ .force(
+ "collide",
+ d3.forceCollide((d) =>
+ d.type === "PERSON" ? personNodePaddedRadius : teamNodeRadius
+ )
+ );
+
+ const svg = d3
+ .create("svg")
+ .attr("viewBox", [0, 0, width, height])
+ .style("user-select", "none");
+ svg.append("g").classed("links", true);
+ svg.append("g").classed("nodes", true);
+
+ let draggedNode = null;
+ let dragOffset = null;
+
+ function mousedown(event, node) {
+ if (draggedNode) {
+ return;
+ }
+ const bounds = svg.node().getBoundingClientRect();
+ simulation.alphaTarget(0.025).restart();
+ draggedNode = node;
+ selectNode(draggedNode);
+ const clickedPoint = {
+ x: event.x - bounds.left,
+ y: event.y - bounds.top,
+ };
+ dragOffset = {
+ dx: clickedPoint.x - draggedNode.x,
+ dy: clickedPoint.y - draggedNode.y,
+ };
+ draggedNode.fx = draggedNode.x;
+ draggedNode.fy = draggedNode.y;
+ }
+
+ function mousemove(event) {
+ if (!draggedNode) {
+ return;
+ }
+ const bounds = svg.node().getBoundingClientRect();
+ const clickedPoint = {
+ x: event.x - bounds.left,
+ y: event.y - bounds.top,
+ };
+ draggedNode.fx = clickedPoint.x - dragOffset.dx;
+ draggedNode.fy = clickedPoint.y - dragOffset.dy;
+ }
+
+ function mouseup(event) {
+ if (!draggedNode) {
+ return;
+ }
+ draggedNode.fx = null;
+ draggedNode.fy = null;
+ draggedNode = null;
+ dragOffset = null;
+ simulation.alphaTarget(0);
+ }
+
+ function* render(_selectNode, _selectedNode) {
+ selectNode = _selectNode;
+ selectedNode = _selectedNode;
+
+ let link = svg
+ .select(".links")
+ .selectAll("line")
+ .data(links, (d) => `${d.from?.id}_${d.to?.id}`);
+ const linkEnter = link
+ .enter()
+ .append("line")
+ .attr("stroke", "#999")
+ .attr("stroke-opacity", 0.6)
+ .attr("stroke-width", strokeWeight);
+ link.exit().remove();
+ link = link.merge(linkEnter);
+
+ let node = svg
+ .select(".nodes")
+ .selectAll("g.node")
+ .data(nodes, (d) => d.id);
+ const nodeEnter = node.enter().append("g").classed("node", true);
+ node.exit().remove();
+ node = node
+ .merge(nodeEnter)
+ // d3.drag() does weird things with quarto's minified version of d3, and
+ // isn't very retina display-friendly... so we manage interactions ourselves
+ .on("mousedown", mousedown);
+ d3.select(document).on("mousemove", mousemove).on("mouseup", mouseup);
+
+ nodeEnter
+ .append("circle")
+ .classed("outline", true)
+ .attr(
+ "r",
+ (d) =>
+ highlightOutlineRadius +
+ (d.type === "PERSON" ? personNodeRadius : teamNodeRadius)
+ )
+ .style("fill", "none")
+ .style("stroke", "#333")
+ .style("stroke-width", highlightStrokeWeight);
+ node
+ .select(".outline")
+ .style("display", (d) => (d.id === selectedNode?.id ? null : "none"));
+
+ nodeEnter
+ .filter((d) => d.type !== "PERSON")
+ .append("circle")
+ .attr("r", teamNodeRadius)
+ .style("fill", (d) => teamColors(d.type));
+
+ nodeEnter
+ .filter((d) => d.type === "PERSON")
+ .append("clipPath")
+ .attr("id", (d) => d.id)
+ .append("circle")
+ .attr("id", (d) => d.id)
+ .attr("r", personNodeRadius);
+
+ nodeEnter
+ .filter((d) => d.type === "PERSON")
+ .append("image")
+ .attr("href", (d) => d.avatarUrl)
+ .attr("x", (d) => -personNodeRadius)
+ .attr("y", (d) => -personNodeRadius)
+ .attr("width", personNodeRadius * 2)
+ .attr("height", personNodeRadius * 2)
+ .attr("clip-path", (d) => `url(#${d.id})`)
+ .attr("preserveAspectRatio", "xMidYMin slice");
+
+ nodeEnter
+ .append("text")
+ .attr("class", "node_label")
+ .style("fill", (d) => (d.type === "PERSON" ? "black" : "white"))
+ .style("dominant-baseline", (d) =>
+ d.type === "PERSON" ? "hanging" : "bottom"
+ )
+ .style("text-anchor", "middle")
+ .style("font-size", "10pt")
+ .text((d) => d.name || d.login);
+ node.select("text").attr("y", (d) => {
+ if (d.type !== "PERSON") {
+ return "0.5em";
+ }
+ if (d.id === selectedNode?.id) {
+ return `${personNodeRadius + 2 * highlightOutlineRadius}px`;
+ }
+ return `${personNodeRadius}px`;
+ });
+
+ nodeEnter.append("title").text((d) => d.name || d.login);
+
+ simulation.on("tick", () => {
+ node.attr("transform", (d) => "translate(" + d.x + "," + d.y + ")");
+
+ link
+ .attr("x1", (d) => d.source.x)
+ .attr("y1", (d) => d.source.y)
+ .attr("x2", (d) => d.target.x)
+ .attr("y2", (d) => d.target.y);
+ });
+
+ invalidation.then(() => simulation.stop());
+
+ yield svg.node();
+ }
+
+ return render;
+}
diff --git a/components/randomAvatars.ojs b/components/randomAvatars.ojs
index 8a18210..7b407cb 100644
--- a/components/randomAvatars.ojs
+++ b/components/randomAvatars.ojs
@@ -1,34 +1,29 @@
-peopleFile = FileAttachment("data/people.json").json();
-
/**
* An observable.js widget that shows profile pictures for ResBaz GitHub Team
* members; see index.qmd for examples. Additionally, some relevant styles are
* in styles/index.css
*
+ * @param peopleData The results of combineAndOverrideGithubData()
* @param teamName A string that should correspond to the name of an entry in
- * data/people.json, under data.organization.teams.nodes
+ * data/people.json under data.organization.teams.nodes,
+ * or a key under teams in data/overrides.json,
* @returns A DOM element that can be embedded via an ojs cell
*/
-function randomAvatars(teamName) {
- const team = peopleFile.data.organization.teams.nodes.find(
- (team) => team.name === teamName
- );
- const people = team.members.nodes
- .map(({ id }) =>
- peopleFile.data.organization.membersWithRole.nodes.find(
- (person) => person.id === id
- )
- )
+function randomAvatars(peopleData, teamId) {
+ const team = peopleData.teamsById[teamId];
+ const people = team.members
+ .map((id) => peopleData.peopleById[id])
.sort(() => 2 * Math.random() - 1)
.slice(0, 5);
const container = d3.create("div").classed("randomAvatars", true);
container
- .selectAll("img")
+ .selectAll("a")
.data(people)
.enter()
+ .append("a")
+ .attr("href", (person) => `./whoWeAre.html#${person.hash}`)
.append("img")
.attr("src", (person) => person.avatarUrl)
.attr("title", (person) => person.name);
- // TODO: link to the Who We Are page, when a profile picture is clicked
return container.node();
}
diff --git a/components/utilities.ojs b/components/utilities.ojs
new file mode 100644
index 0000000..a26a3c0
--- /dev/null
+++ b/components/utilities.ojs
@@ -0,0 +1,81 @@
+people = FileAttachment("data/people.json").json();
+overrides = FileAttachment("data/overrides.json").json();
+
+function combineAndOverrideGithubData() {
+ const peopleById = {
+ // Include people manually added in overrides.json, that may not have a
+ // github login (or their info hasn't been queried yet by
+ // .github/workflows/build.yml, e.g. during local development)
+ ...overrides.people,
+ ...Object.fromEntries(
+ people.data.organization.membersWithRole.nodes.map((person) => [
+ person.login,
+ {
+ ...person,
+ // Github stores people by an illegible hash; we want to select +
+ // override data using Github usernames as ids (but still use
+ // hashes for url navigation)
+ hash: person.id,
+ id: person.login,
+ type: "PERSON",
+ // Override github profile information with details in overrides.json
+ ...(overrides.people[person?.login] || {}),
+ },
+ ])
+ ),
+ };
+
+ const peopleByHash = Object.fromEntries(
+ Object.values(peopleById).map((person) => [person.hash, person])
+ );
+
+ const teamsById = {
+ // Include this separately for manual "teams" that aren't on Github
+ ...overrides.teams,
+ ...Object.fromEntries(
+ people.data.organization.teams.nodes.map((team) => {
+ const teamId = team.name.toLowerCase().replace(/\s+/g, "_");
+ return [
+ teamId,
+ {
+ id: teamId,
+ name: team.name,
+ type: "FESTIVAL", // For non-festival "teams," add an override!
+ members: team.members.nodes.map(({ id }) => peopleByHash[id].login),
+ // Override any github teams with details in overrides.json
+ ...(overrides.teams[teamId] || {}),
+ },
+ ];
+ })
+ ),
+ };
+ Object.entries(teamsById).forEach(([teamId, team]) => {
+ // Some extra fields that we don't want to have to hand-code
+ // in overrides.json
+ if (!team.hash) {
+ team.id = teamId;
+ team.hash = teamId;
+ }
+ if (!team.type) {
+ team.type = "FESTIVAL";
+ }
+ });
+
+ const nodes = [...Object.values(peopleById), ...Object.values(teamsById)];
+ const links = [];
+ Object.values(teamsById).forEach((team) => {
+ team.members.forEach((member) => {
+ links.push({ source: member, target: team.id });
+ });
+ });
+
+ return {
+ peopleById,
+ peopleByHash,
+ teamsById,
+ graph: {
+ nodes,
+ links,
+ },
+ };
+}
diff --git a/data/overrides.json b/data/overrides.json
new file mode 100644
index 0000000..f0346e0
--- /dev/null
+++ b/data/overrides.json
@@ -0,0 +1,18 @@
+{
+ "teams": {
+ "festival2024": {
+ "name": "2024 Festival Organizers"
+ },
+ "coffee_and_code": {
+ "type": "WEEKLY"
+ },
+ "hacky_hour": {
+ "type": "WEEKLY"
+ }
+ },
+ "people": {
+ "alex-r-bigelow": {
+ "bio": "I research how (and build software for!) people as they think about, reshape, and visualize data"
+ }
+ }
+}
diff --git a/data/people.json b/data/people.json
index 6464aaa..74a463b 100644
--- a/data/people.json
+++ b/data/people.json
@@ -7,15 +7,33 @@
"name": "Website Team",
"members": {
"nodes": [
- { "id": "MDQ6VXNlcjc0MjYzMw==" },
- { "id": "MDQ6VXNlcjEyMTU4NzM=" },
- { "id": "MDQ6VXNlcjE5Mzk4MTM=" },
- { "id": "MDQ6VXNlcjcwODIwMjU=" },
- { "id": "MDQ6VXNlcjExMDIzMzE3" },
- { "id": "MDQ6VXNlcjEyMDIyMDc2" },
- { "id": "MDQ6VXNlcjIxMTI5NjM5" },
- { "id": "MDQ6VXNlcjM4OTYyMjQz" },
- { "id": "U_kgDOBef8kg" }
+ {
+ "id": "MDQ6VXNlcjc0MjYzMw=="
+ },
+ {
+ "id": "MDQ6VXNlcjEyMTU4NzM="
+ },
+ {
+ "id": "MDQ6VXNlcjE5Mzk4MTM="
+ },
+ {
+ "id": "MDQ6VXNlcjcwODIwMjU="
+ },
+ {
+ "id": "MDQ6VXNlcjExMDIzMzE3"
+ },
+ {
+ "id": "MDQ6VXNlcjEyMDIyMDc2"
+ },
+ {
+ "id": "MDQ6VXNlcjIxMTI5NjM5"
+ },
+ {
+ "id": "MDQ6VXNlcjM4OTYyMjQz"
+ },
+ {
+ "id": "U_kgDOBef8kg"
+ }
]
}
},
@@ -23,11 +41,21 @@
"name": "Governance Task Force",
"members": {
"nodes": [
- { "id": "MDQ6VXNlcjc0MjYzMw==" },
- { "id": "MDQ6VXNlcjEyMTU4NzM=" },
- { "id": "MDQ6VXNlcjIxMTI5NjM5" },
- { "id": "MDQ6VXNlcjU2NzAyNjAw" },
- { "id": "U_kgDOBef8kg" }
+ {
+ "id": "MDQ6VXNlcjc0MjYzMw=="
+ },
+ {
+ "id": "MDQ6VXNlcjEyMTU4NzM="
+ },
+ {
+ "id": "MDQ6VXNlcjIxMTI5NjM5"
+ },
+ {
+ "id": "MDQ6VXNlcjU2NzAyNjAw"
+ },
+ {
+ "id": "U_kgDOBef8kg"
+ }
]
}
},
@@ -35,20 +63,48 @@
"name": "Festival2024",
"members": {
"nodes": [
- { "id": "MDQ6VXNlcjc0MjYzMw==" },
- { "id": "MDQ6VXNlcjEyMTU4NzM=" },
- { "id": "MDQ6VXNlcjE5Mzk4MTM=" },
- { "id": "MDQ6VXNlcjM4ODMyNDE=" },
- { "id": "MDQ6VXNlcjEyNjkxOTE4" },
- { "id": "MDQ6VXNlcjE5ODIxMTcx" },
- { "id": "MDQ6VXNlcjIxMTI5NjM5" },
- { "id": "MDQ6VXNlcjI1NDA0Nzgz" },
- { "id": "MDQ6VXNlcjM4OTYyMjQz" },
- { "id": "MDQ6VXNlcjQ2NjEyOTMz" },
- { "id": "MDQ6VXNlcjY4NDAzMzQw" },
- { "id": "U_kgDOBef8kg" },
- { "id": "U_kgDOBewVSw" },
- { "id": "U_kgDOCR6ywQ" }
+ {
+ "id": "MDQ6VXNlcjc0MjYzMw=="
+ },
+ {
+ "id": "MDQ6VXNlcjEyMTU4NzM="
+ },
+ {
+ "id": "MDQ6VXNlcjE5Mzk4MTM="
+ },
+ {
+ "id": "MDQ6VXNlcjM4ODMyNDE="
+ },
+ {
+ "id": "MDQ6VXNlcjEyNjkxOTE4"
+ },
+ {
+ "id": "MDQ6VXNlcjE5ODIxMTcx"
+ },
+ {
+ "id": "MDQ6VXNlcjIxMTI5NjM5"
+ },
+ {
+ "id": "MDQ6VXNlcjI1NDA0Nzgz"
+ },
+ {
+ "id": "MDQ6VXNlcjM4OTYyMjQz"
+ },
+ {
+ "id": "MDQ6VXNlcjQ2NjEyOTMz"
+ },
+ {
+ "id": "MDQ6VXNlcjY4NDAzMzQw"
+ },
+ {
+ "id": "U_kgDOBef8kg"
+ },
+ {
+ "id": "U_kgDOBewVSw"
+ },
+ {
+ "id": "U_kgDOCR6ywQ"
+ }
]
}
},
@@ -56,9 +112,15 @@
"name": "Hacky Hour",
"members": {
"nodes": [
- { "id": "MDQ6VXNlcjc0MjYzMw==" },
- { "id": "MDQ6VXNlcjY5NDcwODk=" },
- { "id": "MDQ6VXNlcjEyNjkxOTE4" }
+ {
+ "id": "MDQ6VXNlcjc0MjYzMw=="
+ },
+ {
+ "id": "MDQ6VXNlcjY5NDcwODk="
+ },
+ {
+ "id": "MDQ6VXNlcjEyNjkxOTE4"
+ }
]
}
},
@@ -66,12 +128,37 @@
"name": "Coffee and Code",
"members": {
"nodes": [
- { "id": "MDQ6VXNlcjc0MjYzMw==" },
- { "id": "MDQ6VXNlcjEyMTU4NzM=" },
- { "id": "MDQ6VXNlcjEyNjkxOTE4" },
- { "id": "MDQ6VXNlcjIxMTI5NjM5" },
- { "id": "MDQ6VXNlcjI1NDA0Nzgz" },
- { "id": "U_kgDOBef8kg" }
+ {
+ "id": "MDQ6VXNlcjc0MjYzMw=="
+ },
+ {
+ "id": "MDQ6VXNlcjEyMTU4NzM="
+ },
+ {
+ "id": "MDQ6VXNlcjEyNjkxOTE4"
+ },
+ {
+ "id": "MDQ6VXNlcjIxMTI5NjM5"
+ },
+ {
+ "id": "MDQ6VXNlcjI1NDA0Nzgz"
+ },
+ {
+ "id": "U_kgDOBef8kg"
+ }
+ ]
+ }
+ },
+ {
+ "name": "GitHub Admins",
+ "members": {
+ "nodes": [
+ {
+ "id": "MDQ6VXNlcjc0MjYzMw=="
+ },
+ {
+ "id": "U_kgDOBef8kg"
+ }
]
}
}
@@ -86,7 +173,10 @@
"bio": "Organic Software Gardener 🍅",
"company": "Exosphere Project",
"avatarUrl": "https://avatars.githubusercontent.com/u/742633?u=204cc5138bfb07ef7332d3fa1d885bbbbe9e7281&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": "https://twitter.com/jpistorius",
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjEyMTU4NzM=",
@@ -95,6 +185,7 @@
"bio": "I research how (and build software for!) people as they think about, reshape, and visualize data",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/1215873?u=9a4a9336866c4a348a0bb220a6e0490963bf32b5&v=4",
+ "websiteUrl": "https://alex-r-bigelow.github.io",
"socialAccounts": {
"edges": [
{
@@ -113,6 +204,7 @@
"bio": "",
"company": "University of Arizona",
"avatarUrl": "https://avatars.githubusercontent.com/u/1939813?u=d39a4cac18c94ef60a298c2ad5fa82bb73fc30c3&v=4",
+ "websiteUrl": null,
"socialAccounts": {
"edges": [
{
@@ -131,6 +223,7 @@
"bio": "Computing Sciences Researcher II at The University of Arizona.",
"company": "The University of Arizona",
"avatarUrl": "https://avatars.githubusercontent.com/u/3883241?u=bb818aa9153eb92f57ae7b878a39faed4988f025&v=4",
+ "websiteUrl": "https://soham.dev",
"socialAccounts": {
"edges": [
{
@@ -149,15 +242,19 @@
"bio": "",
"company": "Natural History Museum, University of Oslo",
"avatarUrl": "https://avatars.githubusercontent.com/u/6617332?u=3836c3ffa014b36b188f4f45297f26461fb39a67&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": "https://sites.google.com/site/meghanbalk/",
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjY5NDcwODk=",
"name": "Ryan Bartelme",
"login": "rbartelme",
- "bio": "Staff Data Scientist in biotechnology research and development",
- "company": "Accelerate Diagnostics",
+ "bio": "Bioinformatician and Data Scientist in biotechnology research and development",
+ "company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/6947089?u=9cc0c86dc9db92eb4358b6b9643b79db33b279f2&v=4",
+ "websiteUrl": "rbartelme.github.io",
"socialAccounts": {
"edges": [
{
@@ -165,6 +262,12 @@
"provider": "TWITTER",
"url": "https://twitter.com/MicrobialBart"
}
+ },
+ {
+ "node": {
+ "provider": "GENERIC",
+ "url": "https://bsky.app/profile/microbialbart.bsky.social"
+ }
}
]
}
@@ -176,6 +279,7 @@
"bio": "-_-",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/7082025?v=4",
+ "websiteUrl": null,
"socialAccounts": {
"edges": [
{
@@ -194,6 +298,7 @@
"bio": "",
"company": "University of Arizona",
"avatarUrl": "https://avatars.githubusercontent.com/u/10335479?u=b9414a8cb122c29d6c8544baea85a84c6baab939&v=4",
+ "websiteUrl": null,
"socialAccounts": {
"edges": [
{
@@ -212,7 +317,10 @@
"bio": "I'm a code curious biologist.",
"company": "University of Alabama at Birmingham",
"avatarUrl": "https://avatars.githubusercontent.com/u/11023317?u=7200ca4bee6441f2ef582f70df5fe39bd236e3ee&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjExNTI3MDQx",
@@ -221,6 +329,7 @@
"bio": "Director of Open Science & Associate Professor at the University of Arizona, Institute for Computation and Data Enabled Insight ",
"company": "University of Arizona, CyVerse",
"avatarUrl": "https://avatars.githubusercontent.com/u/11527041?u=2cefefd17d2dc2ec8243b7a1f53a620f1fde2ff4&v=4",
+ "websiteUrl": "tysonswetnam.com",
"socialAccounts": {
"edges": [
{
@@ -245,6 +354,7 @@
"bio": "",
"company": "University of Arizona, CCT Data Science",
"avatarUrl": "https://avatars.githubusercontent.com/u/12022076?u=377f60f40b83a81b1e57ef8518406bc38ce6748f&v=4",
+ "websiteUrl": null,
"socialAccounts": {
"edges": [
{
@@ -263,7 +373,10 @@
"bio": null,
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/12691918?u=a1c7d45e5755e99746ae358919406cc7f163b192&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjE5ODIxMTcx",
@@ -272,7 +385,10 @@
"bio": "PhD Student at the University of Arizona's School of Information",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/19821171?u=3cca330b757c209c3c1547844a3ad81508304b58&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": "https://lwdozal.github.io/",
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjIwMzA1NzM0",
@@ -281,6 +397,7 @@
"bio": "Staring at the universe's data in the dark.",
"company": "Princeton Plasma Physics Lab; Steward Obs",
"avatarUrl": "https://avatars.githubusercontent.com/u/20305734?u=84a111e22eef413d58e1370acea7cb12d075fc05&v=4",
+ "websiteUrl": "https://astrochun.github.io",
"socialAccounts": {
"edges": [
{
@@ -297,9 +414,12 @@
"name": "Heidi Steiner",
"login": "hidyverse",
"bio": "",
- "company": "University of Arizona",
+ "company": "@Boehringer-Ingelheim",
"avatarUrl": "https://avatars.githubusercontent.com/u/21129639?u=f02dbb9a9ecfad325fa0ead8378f8d77f9150012&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjIyMzgxNTM2",
@@ -308,7 +428,10 @@
"bio": "",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/22381536?u=5925008755e77dd5f884bd288ed6c0ff6f29a25d&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjI1MjM1MjI4",
@@ -317,7 +440,10 @@
"bio": "Librarian @ University of Arizona\r\nDirector, Catalyst Studios\r\n@resbazaz organizer\r\n",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/25235228?u=84becdeac90a0ca8727cfcbfac7988ba13baca46&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjI1NDA0Nzgz",
@@ -326,6 +452,7 @@
"bio": "Scientific Programmer & Educator at University of Arizona",
"company": "University of Arizona, @cct-datascience",
"avatarUrl": "https://avatars.githubusercontent.com/u/25404783?u=bf39b8163e91fb40423676c1806a9fc1ed665c0c&v=4",
+ "websiteUrl": "www.ericrscott.com",
"socialAccounts": {
"edges": [
{
@@ -356,7 +483,10 @@
"bio": "",
"company": "University of Arizona's iSchool",
"avatarUrl": "https://avatars.githubusercontent.com/u/34466941?u=c00f55a3718179e6d8e73acf75d18f3373a59da9&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjM0NDg2MTU0",
@@ -365,7 +495,10 @@
"bio": "Turkeys make excellent companions.",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/34486154?v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": "MagicMilly.github.io",
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjM2MTczNDkw",
@@ -374,6 +507,7 @@
"bio": "Computational geneticist",
"company": "NIH",
"avatarUrl": "https://avatars.githubusercontent.com/u/36173490?v=4",
+ "websiteUrl": "https://www.linkedin.com/in/joanneberghout/",
"socialAccounts": {
"edges": [
{
@@ -392,7 +526,10 @@
"bio": "Data Scientist | PhD, University of Arizona | R/RStudio Evangelist",
"company": "University of Arizona",
"avatarUrl": "https://avatars.githubusercontent.com/u/38962243?u=7ec452e5b8489ddbd966d22fdd5984332225c2ad&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": "https://gregtchism.com/",
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjQxNzA2OTE1",
@@ -401,7 +538,10 @@
"bio": "",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/41706915?u=f94237b4dc3896de97d3fd66872ac172fb638337&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjQ2NjEyOTMz",
@@ -410,7 +550,10 @@
"bio": "Astronomer, Data Scientist, Space Science & EO Enthusiast",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/46612933?v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjQ3NzY2MDc0",
@@ -419,7 +562,10 @@
"bio": "",
"company": "GSA",
"avatarUrl": "https://avatars.githubusercontent.com/u/47766074?u=6e52d4344ed85cd5c8b5e873ec28f1d5e74907e9&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjU2NzAyNjAw",
@@ -428,6 +574,7 @@
"bio": "",
"company": "University of Arizona",
"avatarUrl": "https://avatars.githubusercontent.com/u/56702600?u=03ece3573c51cb41e21197f7c2071d122d5e25a8&v=4",
+ "websiteUrl": "https://liaossanna.wixsite.com/liaos",
"socialAccounts": {
"edges": [
{
@@ -446,7 +593,10 @@
"bio": null,
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/61329916?v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "MDQ6VXNlcjY4NDAzMzQw",
@@ -455,6 +605,7 @@
"bio": "PhD Student in Ecological and Environmental Informatics,\r\nSchool of Informatics, Computing, and Cyber Systems\r\n \r\n\r\n",
"company": "Northern Arizona University",
"avatarUrl": "https://avatars.githubusercontent.com/u/68403340?u=d3e846be891006b37a7aae3b74c7ecde9d0ab6fd&v=4",
+ "websiteUrl": null,
"socialAccounts": {
"edges": [
{
@@ -473,7 +624,10 @@
"bio": null,
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/72940286?u=c0d118c3c830aa038eb2993753b42979431b3dd2&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "U_kgDOBdICzA",
@@ -482,7 +636,10 @@
"bio": "",
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/97649356?v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "U_kgDOBef8kg",
@@ -491,7 +648,10 @@
"bio": "",
"company": "University of Arizona",
"avatarUrl": "https://avatars.githubusercontent.com/u/99089554?u=1441d55ea7637555aca31523963c26a68df6f57f&v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "U_kgDOBewVSw",
@@ -500,7 +660,10 @@
"bio": null,
"company": null,
"avatarUrl": "https://avatars.githubusercontent.com/u/99358027?v=4",
- "socialAccounts": { "edges": [] }
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
},
{
"id": "U_kgDOCR6ywQ",
@@ -508,8 +671,11 @@
"login": "ejahnUA",
"bio": "",
"company": "University of Arizona",
- "avatarUrl": "https://avatars.githubusercontent.com/u/153006785?u=d14316c1567ab29135738cc82d41d37607b9963f&v=4",
- "socialAccounts": { "edges": [] }
+ "avatarUrl": "https://avatars.githubusercontent.com/u/153006785?u=bafb3ce0c2ce02e9812c805a17950ab0e4445c83&v=4",
+ "websiteUrl": null,
+ "socialAccounts": {
+ "edges": []
+ }
}
]
}
diff --git a/data/toyPeople.json b/data/toyPeople.json
new file mode 100644
index 0000000..4ada482
--- /dev/null
+++ b/data/toyPeople.json
@@ -0,0 +1,66 @@
+{
+ "data": {
+ "organization": {
+ "teams": {
+ "nodes": [
+ {
+ "name": "Hacky Hour",
+ "members": {
+ "nodes": [
+ { "id": "cat" },
+ { "id": "mouse" },
+ { "id": "squirrel" }
+ ]
+ }
+ },
+ {
+ "name": "Coffee and Code",
+ "members": {
+ "nodes": [{ "id": "dog" }, { "id": "cat" }]
+ }
+ }
+ ]
+ },
+ "membersWithRole": {
+ "nodes": [
+ {
+ "id": "dog",
+ "name": "Dog",
+ "login": "dog",
+ "bio": "The best dog ever",
+ "company": "Pets, Inc.",
+ "avatarUrl": "https://picsum.photos/id/237/200",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "cat",
+ "name": "Cat",
+ "login": "cat",
+ "bio": "wut",
+ "company": "Pets, Inc.",
+ "avatarUrl": "https://picsum.photos/id/238/200",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "mouse",
+ "name": "Mouse",
+ "login": "mouse",
+ "bio": "i heart cheese",
+ "company": "roDENTS",
+ "avatarUrl": "https://picsum.photos/id/239/200",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "squirrel",
+ "name": "Squirrel",
+ "login": "squirrel",
+ "bio": "you'll never find my acorns",
+ "company": "roDENTS",
+ "avatarUrl": "https://picsum.photos/id/240/200",
+ "socialAccounts": { "edges": [] }
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/img/logos/facebook.svg b/img/logos/facebook.svg
new file mode 100644
index 0000000..2dc423e
--- /dev/null
+++ b/img/logos/facebook.svg
@@ -0,0 +1,44 @@
+
+
diff --git a/img/logos/github.svg b/img/logos/github.svg
new file mode 100644
index 0000000..14eab4d
--- /dev/null
+++ b/img/logos/github.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/img/logos/instagram.svg b/img/logos/instagram.svg
new file mode 100644
index 0000000..e042935
--- /dev/null
+++ b/img/logos/instagram.svg
@@ -0,0 +1,101 @@
+
+
diff --git a/img/logos/link.svg b/img/logos/link.svg
new file mode 100644
index 0000000..c15b509
--- /dev/null
+++ b/img/logos/link.svg
@@ -0,0 +1,70 @@
+
+
diff --git a/img/logos/linkedin.svg b/img/logos/linkedin.svg
new file mode 100644
index 0000000..8e991c1
--- /dev/null
+++ b/img/logos/linkedin.svg
@@ -0,0 +1,54 @@
+
+
diff --git a/img/logos/mastodon.svg b/img/logos/mastodon.svg
new file mode 100644
index 0000000..fdab6fc
--- /dev/null
+++ b/img/logos/mastodon.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/img/logos/pinterest.svg b/img/logos/pinterest.svg
new file mode 100644
index 0000000..c52eefe
--- /dev/null
+++ b/img/logos/pinterest.svg
@@ -0,0 +1,45 @@
+
+
diff --git a/img/logos/reddit.svg b/img/logos/reddit.svg
new file mode 100644
index 0000000..0afe591
--- /dev/null
+++ b/img/logos/reddit.svg
@@ -0,0 +1,49 @@
+
+
diff --git a/img/logos/twitter.svg b/img/logos/twitter.svg
new file mode 100644
index 0000000..802de75
--- /dev/null
+++ b/img/logos/twitter.svg
@@ -0,0 +1,58 @@
+
+
diff --git a/index.qmd b/index.qmd
index 16d25ae..740f40c 100644
--- a/index.qmd
+++ b/index.qmd
@@ -10,7 +10,10 @@ title-block-banner-color: white
---
```{ojs}
+import { combineAndOverrideGithubData } from './components/utilities.ojs';
import { randomAvatars } from './components/randomAvatars.ojs';
+
+peopleData = combineAndOverrideGithubData();
```
@@ -52,7 +55,7 @@ _(Optionally) RSVP for our events at Meetup: [Our MeetUp](https://www.meetup.com
**A few people you're likely to see**:
```{ojs}
-randomAvatars("Coffee and Code");
+randomAvatars(peopleData, "coffee_and_code");
```
:::
@@ -74,7 +77,7 @@ randomAvatars("Coffee and Code");
**A few people you're likely to see**:
```{ojs}
-randomAvatars("Hacky Hour");
+randomAvatars(peopleData, "hacky_hour");
```
:::
@@ -102,7 +105,7 @@ randomAvatars("Hacky Hour");
**A few people you're likely to see**:
```{ojs}
-randomAvatars("Festival2024");
+randomAvatars(peopleData, "festival2024");
```
:::
diff --git a/styles/whoWeAre.css b/styles/whoWeAre.css
new file mode 100644
index 0000000..5e68464
--- /dev/null
+++ b/styles/whoWeAre.css
@@ -0,0 +1,8 @@
+.socialIcons {
+ display: flex;
+ gap: 0.5em;
+ margin: 0.5em 0;
+}
+.socialIcons a {
+ text-decoration: none !important;
+}
diff --git a/theme.scss b/theme.scss
index a6f5754..e9d9c42 100644
--- a/theme.scss
+++ b/theme.scss
@@ -18,7 +18,7 @@ $gray-800: #333 !default;
$gray-900: #212529 !default;
$black: #000 !default;
-$blue: #007bff !default;
+$blue: #1e58ac !default;
$indigo: #6610f2 !default;
$purple: #772953 !default;
$pink: #e83e8c !default;
diff --git a/whoWeAre.qmd b/whoWeAre.qmd
index 328fc18..197f383 100644
--- a/whoWeAre.qmd
+++ b/whoWeAre.qmd
@@ -1,5 +1,98 @@
---
-title: "Who We Are"
+layout: default
+css: styles/whoWeAre.css
+execute:
+ echo: false
---
-TODO
\ No newline at end of file
+::: { .column-screen-left }
+
+```{ojs}
+// A lot of setup here, mostly so we can have a common state
+// between nodeLinkDiagram and the sidebar
+import { combineAndOverrideGithubData } from './components/utilities.ojs';
+import { nodeLinkDiagram } from './components/nodeLinkDiagram.ojs';
+
+peopleData = combineAndOverrideGithubData();
+
+mutable selectedNode = null
+
+// On load, and when the back button is pressed, select the node indicated by the URL (if there is one)
+function handleHashChange () {
+ mutable selectedNode = window.location.hash
+ ? peopleData.graph.nodes.find(node => node.hash === window.location.hash.slice(1)) || null
+ : null
+}
+
+// More ojs weirdness: need to wrap event assignments in a cell
+// or `undefined` will show up in the page
+dummy = {
+ window.addEventListener('hashchange', handleHashChange);
+ window.addEventListener('load', handleHashChange);
+}
+
+render = nodeLinkDiagram(peopleData.graph.nodes, peopleData.graph.links);
+diagram = render((node) => {
+ mutable selectedNode = node;
+ window.location.hash = node.hash;
+}, selectedNode);
+```
+:::
+
+::: { .column-margin }
+```{ojs}
+{
+ if (selectedNode === null) {
+ return md`
+This is a diagram of attendees, current and past organizers, and
+their relationships to various ResBaz Arizona events.
+
+*Click a node for more information*
+ `;
+ } else if (selectedNode.type === 'PERSON') {
+ const header = selectedNode.name
+ ? md`# ${selectedNode.name}`
+ : (selectedNode.login
+ ? md`# ${selectedNode.login}`
+ : '');
+
+ const profilePic = selectedNode.avatarUrl ? html`
+
+ `) || '';
+ const socialIcons = html`
Error! Unknown node:
${
+ JSON.stringify(selectedNode, null, 2)
+ }`;
+}
+```
+:::
\ No newline at end of file