diff --git a/src/components/pages/home/learn/learn.jsx b/src/components/pages/home/learn/learn.jsx index 3992c2e6f..d333857cf 100644 --- a/src/components/pages/home/learn/learn.jsx +++ b/src/components/pages/home/learn/learn.jsx @@ -1,49 +1,64 @@ -import React from 'react'; +import { useStaticQuery, graphql } from 'gatsby'; +import React, { Fragment } from 'react'; +import BlogPostCard from 'components/shared/blog-post-card'; import Container from 'components/shared/container'; import Heading from 'components/shared/heading'; -import List from 'components/shared/list'; +import useWindowSize from 'hooks/use-window-size'; -const title = 'Latest News & Blogs'; +const TABLET_WIDTH = 1024; +const title = 'Learn about Cilium & eBPF'; -const featuredBlogs = { - title: 'Featured Blogs', - items: [ - { - linkUrl: 'https://isovalent.com/blog/post/2021-09-aws-eks-anywhere-chooses-cilium', - linkTarget: '_blank', - linkText: 'AWS picks Cilium for Networking & Security on EKS Anywhere', - }, - { - linkUrl: 'https://cilium.io/blog/2021/08/03/best-of-echo', - linkText: 'eBPF and Cilium Office Hours - Highlights from Season 1', - }, - { - linkUrl: 'https://cilium.io/blog/2021/05/20/cilium-110', - linkText: - 'Cilium 1.10: WireGuard, BGP Support, Egress IP Gateway, New Cilium CLI, XDP Load Balancer, Alibaba Cloud Integration and more', - }, - { - linkUrl: 'https://cilium.io/blog/2021/05/11/cni-benchmark', - linkText: 'CNI Benchmark: Understanding Cilium Network Performance', - }, - { - linkUrl: 'https://cilium.io/blog/2021/04/19/openshift-certification', - linkText: 'Introducing the Cilium Certified OpenShift Plug-in', - }, - ], - buttonUrl: '/blog', - buttonText: 'Read more', +const Learn = () => { + const { width } = useWindowSize(); + const isDesktop = width >= TABLET_WIDTH; + const { + allMdx: { posts }, + } = useStaticQuery(graphql` + query blogQuery { + allMdx(sort: { order: DESC, fields: frontmatter___date }, limit: 5) { + posts: nodes { + frontmatter { + path + externalUrl + title + date(locale: "en", formatString: "MMM DD, yyyy") + ogImageUrl + ogImage { + childImageSharp { + gatsbyImageData(width: 512) + } + } + ogSummary + } + } + } + } + `); + + return ( +
+ + {title} +
+ {posts.map(({ frontmatter }, index) => ( + + {index === 0 ? ( + + ) : ( + + )} + + ))} +
+
+
+ ); }; -const Learn = () => ( -
- - {title} -
- -
-
-
-); export default Learn; diff --git a/src/components/shared/blog-post-card/blog-post-card.jsx b/src/components/shared/blog-post-card/blog-post-card.jsx index ce6fee161..55fe472a8 100644 --- a/src/components/shared/blog-post-card/blog-post-card.jsx +++ b/src/components/shared/blog-post-card/blog-post-card.jsx @@ -1,3 +1,4 @@ +import classNames from 'classnames'; import { GatsbyImage, getImage } from 'gatsby-plugin-image'; import PropTypes from 'prop-types'; import React from 'react'; @@ -7,7 +8,55 @@ import ExternalLinkIcon from 'icons/external-link.inline.svg'; import CiliumLogo from './images/cilium-logo.inline.svg'; -function BlogPostCard({ +const coverStyles = { + base: 'shrink-0', + lg: 'sm:max-w-[512px]', + md: 'min-h-[168px] sm:max-h-[168px] sm:max-w-[320px]', + sm: 'min-h-[107px] sm:max-h-[107px] sm:max-w-[198px]', +}; + +const titleStyles = { + lg: 'text-2xl lg:text-3xl font-semibold', + md: 'md:text-lg font-bold', + sm: 'md:text-lg font-bold', +}; + +const BlogCover = ({ ogImage, title, coverUrl, coverClassNames }) => { + let content = null; + if (ogImage) { + content = ( + + ); + } else if (coverUrl) { + content = ( + {title} + ); + } else if (!ogImage && !coverUrl) { + content = ( +
+ +
+ ); + } + return content; +}; + +const BlogPostCard = ({ path, ogImage, ogImageUrl, @@ -16,65 +65,79 @@ function BlogPostCard({ ogSummary: summary, categories, externalUrl, -}) { + size, + className, + isLandscapeView, +}) => { const url = externalUrl !== '' ? externalUrl : null; const coverUrl = ogImageUrl !== '' ? ogImageUrl : null; - + const coverClassNames = classNames( + coverStyles.base, + coverStyles[size], + isLandscapeView && 'self-center' + ); return ( - {ogImage && ( - - )} - {coverUrl && ( - {title} - )} - {!ogImage && !coverUrl && ( -
- -
- )} - -
+ +
{date} -

+

{title}

-

{summary}

-
- {categories?.map((category) => ( - +

- {category} - - ))} - {url && ( -

- External - + {summary} +

+
+ {categories?.map((category) => ( + + {category} + + ))} + {url && ( +
+ External + +
+ )}
- )} -
-
+ + )} +
); -} +}; BlogPostCard.propTypes = { path: PropTypes.string, @@ -89,6 +152,9 @@ BlogPostCard.propTypes = { title: PropTypes.string.isRequired, ogSummary: PropTypes.string, categories: PropTypes.arrayOf(PropTypes.string), + size: PropTypes.oneOf(Object.keys(titleStyles)), + className: PropTypes.string, + isLandscapeView: PropTypes.bool, }; BlogPostCard.defaultProps = { @@ -98,6 +164,9 @@ BlogPostCard.defaultProps = { externalUrl: null, ogSummary: null, categories: null, + size: Object.keys(titleStyles)[1], + className: null, + isLandscapeView: false, }; export default BlogPostCard; diff --git a/src/hooks/use-window-size.js b/src/hooks/use-window-size.js new file mode 100644 index 000000000..6c3af3034 --- /dev/null +++ b/src/hooks/use-window-size.js @@ -0,0 +1,29 @@ +import { useState, useEffect } from 'react'; +// Hook +function useWindowSize() { + // Initialize state with undefined width/height so server and client renders match + // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/ + const [windowSize, setWindowSize] = useState({ + width: undefined, + height: undefined, + }); + useEffect(() => { + // Handler to call on window resize + function handleResize() { + // Set window width/height to state + setWindowSize({ + width: window.innerWidth, + height: window.innerHeight, + }); + } + // Add event listener + window.addEventListener('resize', handleResize); + // Call handler right away so state gets updated with initial window size + handleResize(); + // Remove event listener on cleanup + return () => window.removeEventListener('resize', handleResize); + }, []); // Empty array ensures that effect is only run on mount + return windowSize; +} + +export default useWindowSize; diff --git a/src/styles/global.css b/src/styles/global.css index e66ebcd54..c3c5543d2 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1,6 +1,7 @@ @layer base { body { @apply text-base text-black antialiased; + -webkit-tap-highlight-color: transparent; } .highlight-words {