diff --git a/gatsby-config.js b/gatsby-config.js
index 5e830b80..1d80f424 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -20,6 +20,13 @@ module.exports = {
path: `${__dirname}/src`,
},
},
+ {
+ resolve: `gatsby-source-filesystem`,
+ options: {
+ name: `images`,
+ path: `${__dirname}/static`,
+ },
+ },
{
resolve: 'gatsby-plugin-manifest',
options: {
diff --git a/gatsby-node.js b/gatsby-node.js
index f32412a0..5d1a55e0 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -68,6 +68,9 @@ exports.createPages = ({ graphql, actions }) => {
component: slash(articleTemplate),
context: {
id: edge.node.id,
+ image: (edge.node.pageAttributes.image || '')
+ .replace(/^\//, '')
+ .replace(/^static\//, ''),
},
});
});
diff --git a/src/Components/Featured-contributor/FeaturedContributor.jsx b/src/Components/Featured-contributor/FeaturedContributor.jsx
index 7af5d2a7..9e2718d9 100644
--- a/src/Components/Featured-contributor/FeaturedContributor.jsx
+++ b/src/Components/Featured-contributor/FeaturedContributor.jsx
@@ -2,14 +2,41 @@ import React from 'react';
import { motion } from 'framer-motion';
import { Calendar, GitCommitHorizontal, MapPin } from 'lucide-react';
import './featured-contributor.css';
-import { Link } from 'gatsby';
+import { Link, graphql, useStaticQuery } from 'gatsby';
+import { GatsbyImage, getImage } from 'gatsby-plugin-image';
const FeaturedContributor = ({ contributor, darkmode }) => {
+ const data = useStaticQuery(graphql`
+ query FeaturedContributorImagesQuery {
+ allFile(
+ filter: {
+ sourceInstanceName: { eq: "images" }
+ extension: { in: ["jpg", "jpeg", "png", "webp", "avif"] }
+ }
+ ) {
+ nodes {
+ relativePath
+ childImageSharp {
+ gatsbyImageData(width: 500, placeholder: BLURRED)
+ }
+ }
+ }
+ }
+ `);
+
if (!contributor) return null;
const pageAttributes = contributor?.node?.pageAttributes;
const { name, image, location, datepublished, intro, firstcommit } =
pageAttributes || {};
+ const normalizeImagePath = (value) =>
+ (value || '').replace(/^\//, '').replace(/^static\//, '');
+ const normalizedPath = normalizeImagePath(image);
+ const matchedImageNode = data.allFile.nodes.find(
+ (node) => node.relativePath === normalizedPath
+ );
+ const optimizedImageData = getImage(matchedImageNode);
+ const fallbackImageSrc = image;
const slug = contributor?.node?.fields?.slug;
return (
{
transition={{ delay: 0.2, duration: 0.4 }}
whileHover={{ scale: 1.02 }}
>
-
+ {optimizedImageData ? (
+
+ ) : (
+
+ )}
diff --git a/src/Components/Search/SearchResults.jsx b/src/Components/Search/SearchResults.jsx
index 592d1deb..01d11190 100644
--- a/src/Components/Search/SearchResults.jsx
+++ b/src/Components/Search/SearchResults.jsx
@@ -1,11 +1,37 @@
import React from 'react';
import './search-result.css';
-import { Link } from 'gatsby';
+import { Link, graphql, useStaticQuery } from 'gatsby';
import { Github, Linkedin } from 'lucide-react';
import { motion } from 'framer-motion';
import XIcon from '../XIcon.jsx';
+import { GatsbyImage, getImage } from 'gatsby-plugin-image';
function SearchResults({ results, darkmode }) {
+ const data = useStaticQuery(graphql`
+ query SearchResultsImagesQuery {
+ allFile(
+ filter: {
+ sourceInstanceName: { eq: "images" }
+ extension: { in: ["jpg", "jpeg", "png", "webp", "avif"] }
+ }
+ ) {
+ nodes {
+ relativePath
+ childImageSharp {
+ gatsbyImageData(
+ width: 50
+ height: 50
+ placeholder: BLURRED
+ )
+ }
+ }
+ }
+ }
+ `);
+
+ const normalizeImagePath = (value) =>
+ (value || '').replace(/^\//, '').replace(/^static\//, '');
+
if (!results || results.length === 0) {
return (
{sortedResults.map(({ item, score }) => {
if (!item) return null;
+ const normalizedPath = normalizeImagePath(item?.image);
+ const matchedImageNode = data.allFile.nodes.find(
+ (node) => node.relativePath === normalizedPath
+ );
+ const optimizedImageData = getImage(matchedImageNode);
return (
-

+ {optimizedImageData ? (
+
+ ) : (
+

+ )}
diff --git a/src/pages/index.js b/src/pages/index.js
index f70aeb77..9c1a4bc2 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -7,6 +7,7 @@ import { Helmet } from 'react-helmet';
import dayjs from 'dayjs';
import axios from 'axios';
import Papa from 'papaparse';
+import { GatsbyImage, getImage } from 'gatsby-plugin-image';
import ContributorsList from '../Components/Contributor/ContributorsList.jsx';
import FeaturedContributor from '../Components/Featured-contributor/FeaturedContributor.jsx';
import Search from '../Components/Search/Search.jsx';
@@ -15,10 +16,29 @@ const IndexPage = (props) => {
const isDesktop = useMediaQuery(theme.breakpoints.up('lg'));
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const { data } = props;
+ const normalizeImagePath = (value) =>
+ (value || '').replace(/^\//, '').replace(/^static\//, '');
+ const imageNodes = data?.allFile?.nodes || [];
+ const getOptimizedImageData = (value) => {
+ const normalizedPath = normalizeImagePath(value);
+ if (!normalizedPath) return null;
+
+ const matchedNode = imageNodes.find(
+ (node) => node.relativePath === normalizedPath
+ );
+ return getImage(matchedNode);
+ };
+
const contributors = data.allAsciidoc.edges;
const [thankYou, setThankYou] = React.useState([]);
const [darkmode, setDarkmode] = React.useState(null);
+ const jenkinsLogoImageData = getOptimizedImageData('/jenkins.png');
+ const randomContributorImagePath = thankYou[6]?.replace(/['"]+/g, '');
+ const randomContributorImageData = getOptimizedImageData(
+ randomContributorImagePath
+ );
+
useEffect(() => {
if (typeof window !== 'undefined') {
const mediaquery =
@@ -124,7 +144,14 @@ const IndexPage = (props) => {
continuous integration and delivery
-
+ {jenkinsLogoImageData ? (
+
+ ) : (
+
+ )}
@@ -183,18 +210,40 @@ const IndexPage = (props) => {
alignItems: 'center',
}}
>
-
+ {randomContributorImageData ? (
+
+ ) : (
+
+ )}
{
export default IndexPage;
export const pageQuery = graphql`
- query {
+ query IndexPageQuery {
allAsciidoc(limit: 1000, sort: { fields: { publicationDate: DESC } }) {
edges {
node {
@@ -312,5 +361,18 @@ export const pageQuery = graphql`
}
}
}
+ allFile(
+ filter: {
+ sourceInstanceName: { eq: "images" }
+ extension: { in: ["jpg", "jpeg", "png", "webp", "avif"] }
+ }
+ ) {
+ nodes {
+ relativePath
+ childImageSharp {
+ gatsbyImageData(width: 120, placeholder: BLURRED)
+ }
+ }
+ }
}
`;
diff --git a/src/templates/contributor-details.jsx b/src/templates/contributor-details.jsx
index b648f46a..f2068844 100644
--- a/src/templates/contributor-details.jsx
+++ b/src/templates/contributor-details.jsx
@@ -10,6 +10,7 @@ import { Github, Linkedin, Mail } from 'lucide-react';
import XIcon from '../Components/XIcon.jsx';
import { motion } from 'framer-motion';
import './contributor-details.css';
+import { GatsbyImage, getImage } from 'gatsby-plugin-image';
function ContributorDetails(props) {
const theme = useTheme();
const isDesktop = useMediaQuery(theme.breakpoints.up('lg'));
@@ -18,9 +19,12 @@ function ContributorDetails(props) {
const title =
props.data.asciidoc.pageAttributes.name +
' - Jenkins Contributor Spotlight';
+ const imageData = getImage(props.data.imageFile);
// 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(() => {
@@ -99,16 +103,38 @@ function ContributorDetails(props) {
}}
>
-
+
+ {imageData ? (
+
+ ) : (
+
+ )}
+