From 707ef8ec0a6dbd023d7d67f3ae66153a184f08a9 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 13 Feb 2026 14:49:18 +0000 Subject: [PATCH 1/3] add previous and next navigation to contributor spotlight pages --- gatsby-node.js | 30 ++++++- src/templates/contributor-details.jsx | 114 ++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index f32412a0..7117900b 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -16,7 +16,10 @@ exports.createPages = ({ graphql, actions }) => { // from the fetched data that you can run queries against. return graphql(` { - allAsciidoc(limit: 1000) { + allAsciidoc( + limit: 1000 + sort: { fields: { publicationDate: DESC } } + ) { edges { node { id @@ -55,7 +58,15 @@ exports.createPages = ({ graphql, actions }) => { const articleTemplate = path.resolve( `./src/templates/contributor-details.jsx` ); - _.each(result.data.allAsciidoc.edges, (edge) => { + const contributors = result.data.allAsciidoc.edges; + + contributors.forEach((edge, index) => { + const previous = index === 0 ? null : contributors[index - 1].node; + + const next = + index === contributors.length - 1 + ? null + : contributors[index + 1].node; // Gatsby uses Redux to manage its internal state. // Plugins and sites can use functions like "createPage" // to interact with Gatsby. @@ -68,6 +79,21 @@ exports.createPages = ({ graphql, actions }) => { component: slash(articleTemplate), context: { id: edge.node.id, + previous: previous + ? { + slug: previous.fields.slug, + title: previous.document.title, + image: previous.pageAttributes.image, + } + : null, + + next: next + ? { + slug: next.fields.slug, + title: next.document.title, + image: next.pageAttributes.image, + } + : null, }, }); }); diff --git a/src/templates/contributor-details.jsx b/src/templates/contributor-details.jsx index 458804b0..4e9bb2e1 100644 --- a/src/templates/contributor-details.jsx +++ b/src/templates/contributor-details.jsx @@ -19,6 +19,7 @@ function ContributorDetails(props) { const title = props.data.asciidoc.pageAttributes.name + ' - Jenkins Contributor Spotlight'; + const { previous, next } = props.pageContext; return ( <> @@ -193,6 +194,119 @@ function ContributorDetails(props) { __html: props.data.asciidoc.html, }} /> + + {previous ? ( + + + + + {previous.title} + + + + Previous Profile + + + {previous.title} + + + + + ) : ( +
+ )} + + {next ? ( + + + + + + Next Profile + + + {next.title} + + + + {next.title} + + + + + + + ) : ( +
+ )} + From 958cd861f63b58f053cafffa9f6f2d09f9ce1485 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 20 Feb 2026 17:33:34 +0000 Subject: [PATCH 2/3] fix: improve visibility of next and previous profile text in dark mode --- src/templates/contributor-details.jsx | 108 ++++++++++++++++++-------- 1 file changed, 77 insertions(+), 31 deletions(-) diff --git a/src/templates/contributor-details.jsx b/src/templates/contributor-details.jsx index 5dc9ab00..85ff6de8 100644 --- a/src/templates/contributor-details.jsx +++ b/src/templates/contributor-details.jsx @@ -19,9 +19,28 @@ function ContributorDetails(props) { props.data.asciidoc.pageAttributes.name + ' - Jenkins Contributor Spotlight'; const { previous, next } = props.pageContext; + const [darkmode, setDarkmode] = React.useState(null); + + useEffect(() => { + if (typeof window !== 'undefined') { + const mediaquery = + window.matchMedia && + window.matchMedia('(prefers-color-scheme: dark)'); + setDarkmode(mediaquery.matches); + const handler = (event) => { + setDarkmode(event.matches); + }; + mediaquery.addEventListener('change', handler); + return () => { + mediaquery.removeEventListener('change', handler); + }; + } + }, []); // State for sanitized HTML - const [sanitizedHTML, setSanitizedHTML] = useState(props.data.asciidoc.html); + const [sanitizedHTML, setSanitizedHTML] = useState( + props.data.asciidoc.html + ); // Sanitize HTML on client side only useEffect(() => { @@ -266,16 +285,16 @@ function ContributorDetails(props) { sx={{ mt: 10, pt: 4, - borderTop: "1px solid #e0e0e0", - display: "flex", + borderTop: '1px solid #e0e0e0', + display: 'flex', flexDirection: { - xs: "column", - sm: "row", + xs: 'column', + sm: 'row', }, - justifyContent: "space-between", + justifyContent: 'space-between', alignItems: { - xs: "stretch", - sm: "center", + xs: 'stretch', + sm: 'center', }, gap: 2, }} @@ -283,10 +302,17 @@ function ContributorDetails(props) { {previous ? ( - - + + - + Previous Profile {previous.title} @@ -325,27 +358,41 @@ function ContributorDetails(props) { - - - + + + Next Profile {next.title} @@ -358,19 +405,18 @@ function ContributorDetails(props) { width={44} height={44} style={{ - borderRadius: "50%", - objectFit: "cover", + borderRadius: '50%', + objectFit: 'cover', }} /> - ) : (
)} From 3e1e6b4eb3f06ade5c67464a1718dfc5da684184 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 6 Mar 2026 01:17:17 +0000 Subject: [PATCH 3/3] use useMediaQuery for dark mode detection and remove unused lodash import --- gatsby-node.js | 1 - src/templates/contributor-details.jsx | 18 +----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 7117900b..d163467d 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,4 +1,3 @@ -const _ = require(`lodash`); const path = require(`path`); const { slash } = require(`gatsby-core-utils`); const { createFilePath } = require(`gatsby-source-filesystem`); diff --git a/src/templates/contributor-details.jsx b/src/templates/contributor-details.jsx index 85ff6de8..04bb0734 100644 --- a/src/templates/contributor-details.jsx +++ b/src/templates/contributor-details.jsx @@ -15,27 +15,11 @@ function ContributorDetails(props) { const isDesktop = useMediaQuery(theme.breakpoints.up('lg')); const isTablet = useMediaQuery(theme.breakpoints.between('lg', 'sm')); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + const darkmode = useMediaQuery('(prefers-color-scheme: dark)'); const title = props.data.asciidoc.pageAttributes.name + ' - Jenkins Contributor Spotlight'; const { previous, next } = props.pageContext; - const [darkmode, setDarkmode] = React.useState(null); - - useEffect(() => { - if (typeof window !== 'undefined') { - const mediaquery = - window.matchMedia && - window.matchMedia('(prefers-color-scheme: dark)'); - setDarkmode(mediaquery.matches); - const handler = (event) => { - setDarkmode(event.matches); - }; - mediaquery.addEventListener('change', handler); - return () => { - mediaquery.removeEventListener('change', handler); - }; - } - }, []); // State for sanitized HTML const [sanitizedHTML, setSanitizedHTML] = useState(