From 614718a299b1319123170440dafc10d3f707acd3 Mon Sep 17 00:00:00 2001
From: Alex Bigelow
Date: Wed, 13 Mar 2024 11:08:31 -0700
Subject: [PATCH 1/5] Add a draft Who We Are page
---
_quarto.yml | 4 +-
components/nodeLinkDiagram.ojs | 160 +++++++++++
data/people.json | 504 +++++++++++++++++++++++++++++++--
data/toyPeople.json | 66 +++++
theme.scss | 2 +-
whoWeAre.qmd | 20 +-
6 files changed, 724 insertions(+), 32 deletions(-)
create mode 100644 components/nodeLinkDiagram.ojs
create mode 100644 data/toyPeople.json
diff --git a/_quarto.yml b/_quarto.yml
index 7e95c71..8d2da68 100644
--- a/_quarto.yml
+++ b/_quarto.yml
@@ -11,8 +11,8 @@ website:
text: Home
- href: index.qmd#events
text: Events
- # - href: whoWeAre.qmd
- # text: Who We Are
+ - 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..0fc0936
--- /dev/null
+++ b/components/nodeLinkDiagram.ojs
@@ -0,0 +1,160 @@
+people = FileAttachment("data/people.json").json();
+
+function nodeLinkDiagram () {
+ const height = width * 0.6;
+
+ const personNodeRadius = 25;
+
+ const teamNodeRadius = 75;
+
+ const strokeWeight = 5;
+
+ const weeklyTeams = new Set([
+ 'coffee_and_code',
+ 'hacky_hour'
+ ]);
+
+ const teamColors = d3.scaleOrdinal(['WEEKLY', 'FESTIVAL'], ['#ea5a2a', '#1e58ac']);
+
+ const peopleById = Object.fromEntries(
+ people.data.organization.membersWithRole.nodes.map((person) => [
+ person.id,
+ {
+ ...person,
+ type: "PERSON"
+ }
+ ])
+ );
+ const nodes = Object.values(peopleById);
+ const links = [];
+ people.data.organization.teams.nodes.forEach((team) => {
+ const teamId = team.name.toLowerCase().replace(/\s+/g, "_");
+ nodes.push({ id: teamId, name: team.name, type: weeklyTeams.has(teamId) ? "WEEKLY" : "FESTIVAL" });
+ team.members.nodes.forEach((member) => {
+ links.push({ source: member.id, target: teamId });
+ });
+ });
+
+ const simulation = d3
+ .forceSimulation(nodes)
+ .force(
+ "link",
+ d3.forceLink(links).id((d) => d.id)
+ )
+ .force(
+ "charge",
+ d3.forceManyBody().strength(-30 * (personNodeRadius + teamNodeRadius))
+ )
+ .force("center", d3.forceCenter(width / 2, height / 2));
+
+ const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
+
+ let draggedNode = null;
+ let selectedNode = null;
+
+ function mousedown(_, node) {
+ if (draggedNode) {
+ return;
+ }
+ simulation.alphaTarget(0.3).restart();
+ draggedNode = selectedNode = node.id;
+ node.fx = node.x;
+ node.fy = node.y;
+ }
+
+ function mousemove(event, node) {
+ if (!draggedNode) {
+ return;
+ }
+ const bounds = svg.node().getBoundingClientRect();
+ node.fx = event.x - bounds.left;
+ node.fy = event.y - bounds.top;
+ }
+
+ function mouseup(_, event) {
+ if (!draggedNode) {
+ return;
+ }
+ draggedNode = null;
+ simulation.alphaTarget(0);
+ node.fx = null;
+ node.fy = null;
+ }
+
+ const link = svg
+ .append("g")
+ .attr("stroke", "#999")
+ .attr("stroke-opacity", 0.6)
+ .selectAll("line")
+ .data(links)
+ .join("line")
+ .attr("stroke-width", strokeWeight);
+
+ const node = svg
+ .append("g")
+ .selectAll("g.node")
+ .data(nodes)
+ .join("g")
+ .classed("node", true)
+ // d3.drag() does weird things with quarto's minified version of d3...
+ // plus, this lets us control clicking vs dragging ourselves
+ .on('mousedown', mousedown)
+ .on('mousemove', mousemove)
+ .on('mouseup', mouseup);
+
+ const teamCircle = node
+ .filter((d) => d.type !== "PERSON")
+ .append("circle")
+ .attr("r", teamNodeRadius)
+ .style("fill", d => teamColors(d.type));
+
+ const clipPath = node
+ .filter((d) => d.type === "PERSON")
+ .append("clipPath")
+ .attr("id", (d) => d.id)
+ .append("circle")
+ .attr("id", (d) => d.id)
+ .attr("r", personNodeRadius);
+
+ // Append images
+ const profileImage = node
+ .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");
+
+ const text = node
+ .append("text")
+ .attr("class", "node_label")
+ .attr("y", (d) =>
+ d.type === "PERSON" ? `${personNodeRadius}px` : "0.5em"
+ )
+ .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);
+
+ node.append("title").text((d) => d.id);
+
+ simulation.on("tick", () => {
+ 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);
+
+ node.attr("transform", (d) => "translate(" + d.x + "," + d.y + ")");
+ });
+
+ // invalidation.then(() => simulation.stop());
+
+ return svg.node();
+}
\ No newline at end of file
diff --git a/data/people.json b/data/people.json
index 4ada482..1023052 100644
--- a/data/people.json
+++ b/data/people.json
@@ -3,20 +3,72 @@
"organization": {
"teams": {
"nodes": [
+ {
+ "name": "Website Team",
+ "members": {
+ "nodes": [
+ { "id": "MDQ6VXNlcjc0MjYzMw==" },
+ { "id": "MDQ6VXNlcjEyMTU4NzM=" },
+ { "id": "MDQ6VXNlcjE5Mzk4MTM=" },
+ { "id": "MDQ6VXNlcjcwODIwMjU=" },
+ { "id": "MDQ6VXNlcjExMDIzMzE3" },
+ { "id": "MDQ6VXNlcjEyMDIyMDc2" },
+ { "id": "MDQ6VXNlcjIxMTI5NjM5" },
+ { "id": "MDQ6VXNlcjM4OTYyMjQz" },
+ { "id": "U_kgDOBef8kg" }
+ ]
+ }
+ },
+ {
+ "name": "Governance Task Force",
+ "members": {
+ "nodes": [
+ { "id": "MDQ6VXNlcjc0MjYzMw==" },
+ { "id": "MDQ6VXNlcjEyMTU4NzM=" },
+ { "id": "MDQ6VXNlcjIxMTI5NjM5" },
+ { "id": "MDQ6VXNlcjU2NzAyNjAw" },
+ { "id": "U_kgDOBef8kg" }
+ ]
+ }
+ },
+ {
+ "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" }
+ ]
+ }
+ },
{
"name": "Hacky Hour",
"members": {
"nodes": [
- { "id": "cat" },
- { "id": "mouse" },
- { "id": "squirrel" }
+ { "id": "MDQ6VXNlcjc0MjYzMw==" },
+ { "id": "MDQ6VXNlcjY5NDcwODk=" },
+ { "id": "MDQ6VXNlcjEyNjkxOTE4" }
]
}
},
{
"name": "Coffee and Code",
"members": {
- "nodes": [{ "id": "dog" }, { "id": "cat" }]
+ "nodes": [
+ { "id": "MDQ6VXNlcjc0MjYzMw==" },
+ { "id": "U_kgDOBef8kg" }
+ ]
}
}
]
@@ -24,39 +76,435 @@
"membersWithRole": {
"nodes": [
{
- "id": "dog",
- "name": "Dog",
- "login": "dog",
- "bio": "The best dog ever",
- "company": "Pets, Inc.",
- "avatarUrl": "https://picsum.photos/id/237/200",
+ "id": "MDQ6VXNlcjc0MjYzMw==",
+ "name": "Julian Pistorius",
+ "login": "julianpistorius",
+ "bio": "Organic Software Gardener 🍅",
+ "company": "Exosphere Project",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/742633?u=204cc5138bfb07ef7332d3fa1d885bbbbe9e7281&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjEyMTU4NzM=",
+ "name": "Alex Bigelow",
+ "login": "alex-r-bigelow",
+ "bio": "I research how (and build software for!) people as they think about, reshape, and visualize data",
+ "company": "Stardog",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/1215873?u=9a4a9336866c4a348a0bb220a6e0490963bf32b5&v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "LINKEDIN",
+ "url": "https://www.linkedin.com/in/alex-bigelow-65145259/"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjE5Mzk4MTM=",
+ "name": "Jeff Oliver",
+ "login": "jcoliver",
+ "bio": "",
+ "company": "University of Arizona",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/1939813?u=d39a4cac18c94ef60a298c2ad5fa82bb73fc30c3&v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/jcoliverAZ"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjM4ODMyNDE=",
+ "name": "Soham Pal",
+ "login": "e-eight",
+ "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",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/dragonbornmonk"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjY2MTczMzI=",
+ "name": "Meghan Balk",
+ "login": "megbalk",
+ "bio": "",
+ "company": "Natural History Museum, University of Oslo",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/6617332?u=3836c3ffa014b36b188f4f45297f26461fb39a67&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjY5NDcwODk=",
+ "name": "Ryan Bartelme",
+ "login": "rbartelme",
+ "bio": "Staff Data Scientist in biotechnology research and development",
+ "company": "Accelerate Diagnostics",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/6947089?u=9cc0c86dc9db92eb4358b6b9643b79db33b279f2&v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/MicrobialBart"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjcwODIwMjU=",
+ "name": "Fernando Rios",
+ "login": "zoidy",
+ "bio": "-_-",
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/7082025?v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "MASTODON",
+ "url": "https://fosstodon.org/@riosfrnd"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjEwMzM1NDc5",
+ "name": "Adriana Picoral",
+ "login": "picoral",
+ "bio": "",
+ "company": "University of Arizona",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/10335479?u=b9414a8cb122c29d6c8544baea85a84c6baab939&v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/adrianapicoral"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjExMDIzMzE3",
+ "name": "Blake Joyce",
+ "login": "bjoyce3",
+ "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": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjExNTI3MDQx",
+ "name": "Tyson L. Swetnam",
+ "login": "tyson-swetnam",
+ "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",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/tswetnam"
+ }
+ },
+ {
+ "node": {
+ "provider": "LINKEDIN",
+ "url": "https://www.linkedin.com/in/tyson-swetnam/"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjEyMDIyMDc2",
+ "name": "Jessica Guo",
+ "login": "jessicaguo",
+ "bio": "",
+ "company": "University of Arizona, CCT Data Science",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/12022076?u=377f60f40b83a81b1e57ef8518406bc38ce6748f&v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/JessicaSGuo"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjEyNjkxOTE4",
+ "name": "Brandon Jernigan",
+ "login": "brandon-jernigan",
+ "bio": null,
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/12691918?u=a1c7d45e5755e99746ae358919406cc7f163b192&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjE5ODIxMTcx",
+ "name": "Laura W. Dozal",
+ "login": "lwdozal",
+ "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": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjIwMzA1NzM0",
+ "name": "Chun Ly",
+ "login": "astrochun",
+ "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",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/astrochunly"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjIxMTI5NjM5",
+ "name": "Heidi Steiner",
+ "login": "hidyverse",
+ "bio": "",
+ "company": "University of Arizona",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/21129639?u=f02dbb9a9ecfad325fa0ead8378f8d77f9150012&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjIyMzgxNTM2",
+ "name": null,
+ "login": "chrisreidy",
+ "bio": "",
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/22381536?u=5925008755e77dd5f884bd288ed6c0ff6f29a25d&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjI1MjM1MjI4",
+ "name": "Jennifer Nichols",
+ "login": "jennytnichols",
+ "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": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjI1NDA0Nzgz",
+ "name": "Eric R. Scott",
+ "login": "Aariq",
+ "bio": "Scientific Programmer & Educator at University of Arizona",
+ "company": "University of Arizona",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/25404783?u=bf39b8163e91fb40423676c1806a9fc1ed665c0c&v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/leafyericscott"
+ }
+ },
+ {
+ "node": {
+ "provider": "MASTODON",
+ "url": "https://fosstodon.org/@LeafyEricScott"
+ }
+ },
+ {
+ "node": {
+ "provider": "LINKEDIN",
+ "url": "https://www.linkedin.com/in/eric-r-scott-phd/"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjM0NDY2OTQx",
+ "name": "Sarah Stueve",
+ "login": "sarahstueve",
+ "bio": "",
+ "company": "University of Arizona's iSchool",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/34466941?u=c00f55a3718179e6d8e73acf75d18f3373a59da9&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjM0NDg2MTU0",
+ "name": null,
+ "login": "MagicMilly",
+ "bio": "Turkeys make excellent companions.",
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/34486154?v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjM2MTczNDkw",
+ "name": "Joanne B",
+ "login": "jberghout",
+ "bio": "Computational geneticist",
+ "company": "NIH",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/36173490?v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/joanneberghout"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjM4OTYyMjQz",
+ "name": "Greg T. Chism",
+ "login": "Gchism94",
+ "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": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjQxNzA2OTE1",
+ "name": "Rebecca Vanderpool",
+ "login": "vanderpoolrr",
+ "bio": "",
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/41706915?u=f94237b4dc3896de97d3fd66872ac172fb638337&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjQ2NjEyOTMz",
+ "name": "Miriam Keppler",
+ "login": "kepplerm",
+ "bio": "Astronomer, Data Scientist, Space Science & EO Enthusiast",
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/46612933?v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjQ3NzY2MDc0",
+ "name": "Drake Asberry",
+ "login": "drakeasberry",
+ "bio": "",
+ "company": "GSA",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/47766074?u=6e52d4344ed85cd5c8b5e873ec28f1d5e74907e9&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjU2NzAyNjAw",
+ "name": "Lia Ossanna",
+ "login": "lossanna",
+ "bio": "",
+ "company": "University of Arizona",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/56702600?u=03ece3573c51cb41e21197f7c2071d122d5e25a8&v=4",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/LiaOssanna"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjYxMzI5OTE2",
+ "name": null,
+ "login": "rbelshe",
+ "bio": null,
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/61329916?v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "MDQ6VXNlcjY4NDAzMzQw",
+ "name": "Emma Reich",
+ "login": "egreich",
+ "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",
+ "socialAccounts": {
+ "edges": [
+ {
+ "node": {
+ "provider": "TWITTER",
+ "url": "https://twitter.com/ecophys_emma"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "id": "MDQ6VXNlcjcyOTQwMjg2",
+ "name": null,
+ "login": "karendelarosa",
+ "bio": null,
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/72940286?u=c0d118c3c830aa038eb2993753b42979431b3dd2&v=4",
+ "socialAccounts": { "edges": [] }
+ },
+ {
+ "id": "U_kgDOBdICzA",
+ "name": "Laura Palacios Falk",
+ "login": "LauraFalk",
+ "bio": "",
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/97649356?v=4",
"socialAccounts": { "edges": [] }
},
{
- "id": "cat",
- "name": "Cat",
- "login": "cat",
- "bio": "wut",
- "company": "Pets, Inc.",
- "avatarUrl": "https://picsum.photos/id/238/200",
+ "id": "U_kgDOBef8kg",
+ "name": null,
+ "login": "val-pf",
+ "bio": "",
+ "company": "University of Arizona",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/99089554?u=1441d55ea7637555aca31523963c26a68df6f57f&v=4",
"socialAccounts": { "edges": [] }
},
{
- "id": "mouse",
- "name": "Mouse",
- "login": "mouse",
- "bio": "i heart cheese",
- "company": "roDENTS",
- "avatarUrl": "https://picsum.photos/id/239/200",
+ "id": "U_kgDOBewVSw",
+ "name": null,
+ "login": "TinaJAZ",
+ "bio": null,
+ "company": null,
+ "avatarUrl": "https://avatars.githubusercontent.com/u/99358027?v=4",
"socialAccounts": { "edges": [] }
},
{
- "id": "squirrel",
- "name": "Squirrel",
- "login": "squirrel",
- "bio": "you'll never find my acorns",
- "company": "roDENTS",
- "avatarUrl": "https://picsum.photos/id/240/200",
+ "id": "U_kgDOCR6ywQ",
+ "name": "Ethan Jahn",
+ "login": "ejahnUA",
+ "bio": "",
+ "company": "University of Arizona",
+ "avatarUrl": "https://avatars.githubusercontent.com/u/153006785?u=d14316c1567ab29135738cc82d41d37607b9963f&v=4",
"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/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..729fe29 100644
--- a/whoWeAre.qmd
+++ b/whoWeAre.qmd
@@ -1,5 +1,23 @@
---
title: "Who We Are"
+page-layout: full
+execute:
+ echo: false
---
-TODO
\ No newline at end of file
+We're a community of current / former / aspirational researchers, data scientists, and friends helping each other to learn new technologies via various different events.
+
+This is a diagram of who is involved in our weekly meetups, and who has has put in the work to organize our bigger festival events.
+
+TODO:
+
+- Click nodes to learn more!
+ - Highlight clicked nodes, show selected event / github profile links
+- Add a bounding box force, use space more effectively
+- Prettier links, fonts
+
+```{ojs}
+import { nodeLinkDiagram } from './components/nodeLinkDiagram.ojs';
+
+nodeLinkDiagram();
+```
\ No newline at end of file
From 45c135af6c6873894b01e8404e6dba72eb25663b Mon Sep 17 00:00:00 2001
From: Alex Bigelow
Date: Wed, 20 Mar 2024 15:24:58 -0700
Subject: [PATCH 2/5] Make nodes selectable, add boundary / gravity forces
---
components/nodeLinkDiagram.ojs | 275 ++++++++++++++++++++++-----------
whoWeAre.qmd | 66 ++++++--
2 files changed, 242 insertions(+), 99 deletions(-)
diff --git a/components/nodeLinkDiagram.ojs b/components/nodeLinkDiagram.ojs
index 0fc0936..987e34a 100644
--- a/components/nodeLinkDiagram.ojs
+++ b/components/nodeLinkDiagram.ojs
@@ -1,13 +1,24 @@
people = FileAttachment("data/people.json").json();
-function nodeLinkDiagram () {
- const height = width * 0.6;
+nodeLinkDiagram = {
+ let selectNode, selectedNode = null;
+
+ const height = globalThis.screen.height - 200;
const personNodeRadius = 25;
+ const personNodePaddedRadius = personNodeRadius + 15;
+
+ const highlightOutlineRadius = 5;
+ const highlightStrokeWeight = 5;
const teamNodeRadius = 75;
- const strokeWeight = 5;
+ const strokeWeight = 3;
+
+ const gravityMultiplier = 0.3;
+ const maxGravityAlpha = 0.0005;
+ const bounceStrength = 2;
+ const chargeStrength = -2000; // -10 * (personNodeRadius + teamNodeRadius);
const weeklyTeams = new Set([
'coffee_and_code',
@@ -43,118 +54,204 @@ function nodeLinkDiagram () {
)
.force(
"charge",
- d3.forceManyBody().strength(-30 * (personNodeRadius + teamNodeRadius))
+ d3.forceManyBody().strength(chargeStrength)
)
- .force("center", d3.forceCenter(width / 2, height / 2));
+ .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);
- const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
+ 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 selectedNode = null;
+ let dragOffset = null;
- function mousedown(_, node) {
+ function mousedown(event, node) {
if (draggedNode) {
return;
}
- simulation.alphaTarget(0.3).restart();
- draggedNode = selectedNode = node.id;
- node.fx = node.x;
- node.fy = node.y;
+ 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
+ };
+ // console.log('down', event, bounds, draggedNode, clickedPoint, dragOffset);
+ draggedNode.fx = draggedNode.x;
+ draggedNode.fy = draggedNode.y;
}
- function mousemove(event, node) {
+ function mousemove(event) {
if (!draggedNode) {
return;
}
const bounds = svg.node().getBoundingClientRect();
- node.fx = event.x - bounds.left;
- node.fy = event.y - bounds.top;
+ const clickedPoint = {
+ x: event.x - bounds.left,
+ y: event.y - bounds.top
+ };
+ // console.log('move', event, bounds, clickedPoint, dragOffset);
+ draggedNode.fx = clickedPoint.x - dragOffset.dx;
+ draggedNode.fy = clickedPoint.y - dragOffset.dy;
}
- function mouseup(_, event) {
+ function mouseup(event) {
if (!draggedNode) {
return;
}
+ // console.log('up', draggedNode, dragOffset);
+ draggedNode.fx = null;
+ draggedNode.fy = null;
draggedNode = null;
+ dragOffset = null;
simulation.alphaTarget(0);
- node.fx = null;
- node.fy = null;
}
- const link = svg
- .append("g")
- .attr("stroke", "#999")
- .attr("stroke-opacity", 0.6)
- .selectAll("line")
- .data(links)
- .join("line")
- .attr("stroke-width", strokeWeight);
-
- const node = svg
- .append("g")
- .selectAll("g.node")
- .data(nodes)
- .join("g")
- .classed("node", true)
- // d3.drag() does weird things with quarto's minified version of d3...
- // plus, this lets us control clicking vs dragging ourselves
- .on('mousedown', mousedown)
- .on('mousemove', mousemove)
- .on('mouseup', mouseup);
-
- const teamCircle = node
- .filter((d) => d.type !== "PERSON")
- .append("circle")
- .attr("r", teamNodeRadius)
- .style("fill", d => teamColors(d.type));
-
- const clipPath = node
- .filter((d) => d.type === "PERSON")
- .append("clipPath")
- .attr("id", (d) => d.id)
- .append("circle")
- .attr("id", (d) => d.id)
- .attr("r", personNodeRadius);
-
- // Append images
- const profileImage = node
- .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");
-
- const text = node
- .append("text")
- .attr("class", "node_label")
- .attr("y", (d) =>
- d.type === "PERSON" ? `${personNodeRadius}px` : "0.5em"
- )
- .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);
+ function * render (_selectNode, _selectedNode) {
+ selectNode = _selectNode;
+ selectedNode = _selectedNode;
- node.append("title").text((d) => d.id);
+ 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);
- simulation.on("tick", () => {
- 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);
+ 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');
- node.attr("transform", (d) => "translate(" + d.x + "," + d.y + ")");
- });
+ 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);
- // invalidation.then(() => simulation.stop());
+ 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 svg.node();
+ return render;
}
\ No newline at end of file
diff --git a/whoWeAre.qmd b/whoWeAre.qmd
index 729fe29..d35283c 100644
--- a/whoWeAre.qmd
+++ b/whoWeAre.qmd
@@ -1,10 +1,63 @@
---
-title: "Who We Are"
-page-layout: full
+layout: default
execute:
echo: false
---
+```{ojs}
+import { nodeLinkDiagram } from './components/nodeLinkDiagram.ojs';
+
+mutable selectedNode = null
+```
+
+::: { .column-screen-left }
+```{ojs}
+graph = nodeLinkDiagram((node) => {
+ mutable selectedNode = node;
+}, selectedNode);
+```
+:::
+
+::: { .column-margin }
+```{ojs}
+{
+ if (selectedNode === null) {
+ return md`
+*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 company = selectedNode.company ? md`*${selectedNode.company}*` : '';
+
+ // TODO: selectedNode.login for github link / icon, selectedNode.socialAccounts list for others
+
+ const bio = selectedNode.bio ? md`${selectedNode.bio}` : '';
+
+ return md`
+${header}
+${profilePic}
+${company}
+${bio}
+`;
+ }
+ // TODO: sidebar for selectedNode.type === 'WEEKLY'
+ // TODO: sidebar for selectedNode.type === 'FESTIVAL'
+ return html`Error! Unknown node:
${
+ JSON.stringify(selectedNode, null, 2)
+ }
`;
+}
+```
+:::
+
We're a community of current / former / aspirational researchers, data scientists, and friends helping each other to learn new technologies via various different events.
This is a diagram of who is involved in our weekly meetups, and who has has put in the work to organize our bigger festival events.
@@ -13,11 +66,4 @@ TODO:
- Click nodes to learn more!
- Highlight clicked nodes, show selected event / github profile links
-- Add a bounding box force, use space more effectively
-- Prettier links, fonts
-
-```{ojs}
-import { nodeLinkDiagram } from './components/nodeLinkDiagram.ojs';
-
-nodeLinkDiagram();
-```
\ No newline at end of file
+- Prettier links, fonts
\ No newline at end of file
From f667a4fa7d438d21603914ff25064612a756d2e2 Mon Sep 17 00:00:00 2001
From: Alex Bigelow
Date: Fri, 29 Mar 2024 17:30:14 -0700
Subject: [PATCH 3/5] Slightly better height
---
components/nodeLinkDiagram.ojs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/components/nodeLinkDiagram.ojs b/components/nodeLinkDiagram.ojs
index 987e34a..d546d7e 100644
--- a/components/nodeLinkDiagram.ojs
+++ b/components/nodeLinkDiagram.ojs
@@ -3,7 +3,7 @@ people = FileAttachment("data/people.json").json();
nodeLinkDiagram = {
let selectNode, selectedNode = null;
- const height = globalThis.screen.height - 200;
+ const height = globalThis.screen.height;
const personNodeRadius = 25;
const personNodePaddedRadius = personNodeRadius + 15;
From c89f44efc5fae0d5a08479507d36369e7556e7ad Mon Sep 17 00:00:00 2001
From: Alex Bigelow
Date: Fri, 5 Apr 2024 14:58:12 -0700
Subject: [PATCH 4/5] Support adding / overriding with custom data
---
.github/workflows/build.yml | 1 +
components/nodeLinkDiagram.ojs | 32 +---
components/randomAvatars.ojs | 25 ++-
components/utilities.ojs | 81 ++++++++++
data/overrides.json | 22 +++
data/people.json | 288 ++++++++++++++++++++++++++-------
img/logos/facebook.svg | 44 +++++
img/logos/github.svg | 57 +++++++
img/logos/instagram.svg | 101 ++++++++++++
img/logos/link.svg | 70 ++++++++
img/logos/linkedin.svg | 54 +++++++
img/logos/mastodon.svg | 47 ++++++
img/logos/pinterest.svg | 45 ++++++
img/logos/reddit.svg | 49 ++++++
img/logos/twitter.svg | 58 +++++++
index.qmd | 9 +-
styles/whoWeAre.css | 8 +
whoWeAre.qmd | 60 +++++--
18 files changed, 925 insertions(+), 126 deletions(-)
create mode 100644 components/utilities.ojs
create mode 100644 data/overrides.json
create mode 100644 img/logos/facebook.svg
create mode 100644 img/logos/github.svg
create mode 100644 img/logos/instagram.svg
create mode 100644 img/logos/link.svg
create mode 100644 img/logos/linkedin.svg
create mode 100644 img/logos/mastodon.svg
create mode 100644 img/logos/pinterest.svg
create mode 100644 img/logos/reddit.svg
create mode 100644 img/logos/twitter.svg
create mode 100644 styles/whoWeAre.css
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/components/nodeLinkDiagram.ojs b/components/nodeLinkDiagram.ojs
index 5fdcd64..b431117 100644
--- a/components/nodeLinkDiagram.ojs
+++ b/components/nodeLinkDiagram.ojs
@@ -1,6 +1,4 @@
-people = FileAttachment("data/people.json").json();
-
-function nodeLinkDiagram() {
+function nodeLinkDiagram(nodes, links) {
let selectNode,
selectedNode = null;
@@ -21,36 +19,11 @@ function nodeLinkDiagram() {
const bounceStrength = 2;
const chargeStrength = -2000; // -10 * (personNodeRadius + teamNodeRadius);
- const weeklyTeams = new Set(["coffee_and_code", "hacky_hour"]);
-
const teamColors = d3.scaleOrdinal(
["WEEKLY", "FESTIVAL"],
["#ea5a2a", "#1e58ac"]
);
- const peopleById = Object.fromEntries(
- people.data.organization.membersWithRole.nodes.map((person) => [
- person.id,
- {
- ...person,
- type: "PERSON",
- },
- ])
- );
- const nodes = Object.values(peopleById);
- const links = [];
- people.data.organization.teams.nodes.forEach((team) => {
- const teamId = team.name.toLowerCase().replace(/\s+/g, "_");
- nodes.push({
- id: teamId,
- name: team.name,
- type: weeklyTeams.has(teamId) ? "WEEKLY" : "FESTIVAL",
- });
- team.members.nodes.forEach((member) => {
- links.push({ source: member.id, target: teamId });
- });
- });
-
const simulation = d3
.forceSimulation(nodes)
.force(
@@ -124,7 +97,6 @@ function nodeLinkDiagram() {
dx: clickedPoint.x - draggedNode.x,
dy: clickedPoint.y - draggedNode.y,
};
- // console.log('down', event, bounds, draggedNode, clickedPoint, dragOffset);
draggedNode.fx = draggedNode.x;
draggedNode.fy = draggedNode.y;
}
@@ -138,7 +110,6 @@ function nodeLinkDiagram() {
x: event.x - bounds.left,
y: event.y - bounds.top,
};
- // console.log('move', event, bounds, clickedPoint, dragOffset);
draggedNode.fx = clickedPoint.x - dragOffset.dx;
draggedNode.fy = clickedPoint.y - dragOffset.dy;
}
@@ -147,7 +118,6 @@ function nodeLinkDiagram() {
if (!draggedNode) {
return;
}
- // console.log('up', draggedNode, dragOffset);
draggedNode.fx = null;
draggedNode.fy = null;
draggedNode = null;
diff --git a/components/randomAvatars.ojs b/components/randomAvatars.ojs
index e40344d..f25dc48 100644
--- a/components/randomAvatars.ojs
+++ b/components/randomAvatars.ojs
@@ -1,33 +1,28 @@
-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);
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..13d5699
--- /dev/null
+++ b/data/overrides.json
@@ -0,0 +1,22 @@
+{
+ "teams": {
+ "festival2024": {
+ "name": "2024 Festival Organizers"
+ },
+ "TestTeam": {
+ "name": "Test Team",
+ "members": ["alex-r-bigelow"]
+ },
+ "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/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 abe590f..d43e252 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
**Who you're likely to see**:
```{ojs}
-randomAvatars("Coffee and Code");
+randomAvatars(peopleData, "coffee_and_code");
```
:::
@@ -74,7 +77,7 @@ randomAvatars("Coffee and Code");
**Who you're likely to see**:
```{ojs}
-randomAvatars("Hacky Hour");
+randomAvatars(peopleData, "hacky_hour");
```
:::
@@ -99,7 +102,7 @@ randomAvatars("Hacky Hour");
**Who 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/whoWeAre.qmd b/whoWeAre.qmd
index a88c31a..197f383 100644
--- a/whoWeAre.qmd
+++ b/whoWeAre.qmd
@@ -1,20 +1,40 @@
---
layout: default
+css: styles/whoWeAre.css
execute:
echo: false
---
+::: { .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
-```
-::: { .column-screen-left }
-```{ojs}
-render = nodeLinkDiagram();
-graph = render((node) => {
+// 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);
```
:::
@@ -24,6 +44,9 @@ graph = render((node) => {
{
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') {
@@ -39,6 +62,20 @@ graph = render((node) => {
const company = selectedNode.company ? md`*${selectedNode.company}*` : '';
+ console.log(selectedNode);
+
+ const extraSocialAccounts = selectedNode?.socialAccounts?.edges
+ ?.filter(edge => edge.node?.provider && edge.node?.url)
+ ?.map(edge => edge.node) || [];
+ const socialIconList = [
+ ...(selectedNode?.websiteUrl ? [{ url: `https://github.com/${selectedNode.websiteUrl}`, provider: 'link' }] : []),
+ ...(selectedNode ? [{ url: `https://github.com/${selectedNode.login}`, provider: 'github' }] : []),
+ ...extraSocialAccounts,
+ ].map(account => html`
+
+ `) || '';
+ const socialIcons = html`${socialIconList}
`;
+
// TODO: selectedNode.login for github link / icon, selectedNode.socialAccounts list for others
const bio = selectedNode.bio ? md`${selectedNode.bio}` : '';
@@ -46,6 +83,7 @@ graph = render((node) => {
return md`
${header}
${profilePic}
+${socialIcons}
${company}
${bio}
`;
@@ -57,14 +95,4 @@ ${bio}
}`;
}
```
-:::
-
-We're a community of current / former / aspirational researchers, data scientists, and friends helping each other to learn new technologies via various different events.
-
-This is a diagram of who is involved in our weekly meetups, and who has has put in the work to organize our bigger festival events.
-
-TODO:
-
-- Click nodes to learn more!
- - Highlight clicked nodes, show selected event / github profile links
-- Prettier links, fonts
\ No newline at end of file
+:::
\ No newline at end of file
From dcd787ff4238aa757fc48a7d7eb035784a61c244 Mon Sep 17 00:00:00 2001
From: Alex Bigelow
Date: Fri, 5 Apr 2024 14:59:42 -0700
Subject: [PATCH 5/5] Cleanup test team
---
data/overrides.json | 4 ----
1 file changed, 4 deletions(-)
diff --git a/data/overrides.json b/data/overrides.json
index 13d5699..f0346e0 100644
--- a/data/overrides.json
+++ b/data/overrides.json
@@ -3,10 +3,6 @@
"festival2024": {
"name": "2024 Festival Organizers"
},
- "TestTeam": {
- "name": "Test Team",
- "members": ["alex-r-bigelow"]
- },
"coffee_and_code": {
"type": "WEEKLY"
},