Skip to content

Commit

Permalink
LMS-42 fetch latest articles from Landgriffon Medium account
Browse files Browse the repository at this point in the history
  • Loading branch information
davidsingal committed Oct 11, 2023
1 parent 364f8b3 commit 4bb4cf4
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 85 deletions.
20 changes: 13 additions & 7 deletions marketing/src/components/blog-card/component.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
/* eslint-disable @next/next/no-img-element */
import { FC } from 'react';

import Image from 'next/image';

export interface BlogProps {
title: string;
subtitle: string;
description: string;
url: string;
image: string;
}

const BlogCard: FC<BlogProps> = ({ title, subtitle, url, image }: BlogProps) => {
const BlogCard: FC<BlogProps> = ({ title, description, url, image }: BlogProps) => {
return (
<div className="bg-blue-900 h-96 w-96 border-1 border-solid border-blue-900">
<a href={url} target="_blank" rel="noreferrer noopener">
<Image src={image} alt="" height={178} width={384} layout="responsive" />
<div className="w-full overflow-hidden">
<img src={image} alt={title} className="w-full h-[178px] object-cover" />
</div>
<div className="p-5">
<h5 className="text-white font-light text-2xl tracking-tight mb-2">{title}</h5>
<p className="font-light text-base text-white mb-3">{subtitle}</p>
<h3 className="text-white font-light text-2xl tracking-tight mb-2 line-clamp-2">
{title}
</h3>
<div
className="font-light text-base text-white mb-3 line-clamp-4"
dangerouslySetInnerHTML={{ __html: description }}
/>
</div>
</a>
</div>
Expand Down
134 changes: 56 additions & 78 deletions marketing/src/containers/blog-posts/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,14 @@ import cx from 'classnames';
import Carousel from 'components/carousel';
import FadeIn from 'components/fade';
import BlogCard from 'components/blog-card';

const BLOGPOSTS = [
{
id: '1',
content: (
<div className="mr-4">
<BlogCard
title="LandGriffon case study."
subtitle="An example analysis of the impact of hypothetical sourcing of 1000 tonnes of palm oil in Aceh, Indonesia, with different levels of spatial sourcing precision and exploration of scenarios."
url="https://medium.com/vizzuality-blog/landgriffon-in-action-an-example-case-study-35b7b9b6638c"
image="/images/service/blogpost/01.jpg"
/>
</div>
),
},
{
id: '2',
content: (
<div className="mr-4">
<BlogCard
title="Evolving ESG regulations."
subtitle="Three key proposals will change the ESG regulatory landscape. The EU CSRD & ESRS, SEC Climate-Related Disclosures and EU Deforestation Law. We summarize each and identify areas companies can prepare."
url="https://medium.com/vizzuality-blog/the-three-upcoming-esg-regulations-every-company-should-pay-attention-to-f6153553552a"
image="/images/service/blogpost/02.jpg"
/>
</div>
),
},
{
id: '3',
content: (
<div className="mr-4">
<BlogCard
title="Complex data, simplified."
subtitle="LandGriffon collates data about company supply chains into one accessible dashboard. Map supply chains, benchmark data, and estimate potential environmental risks."
url="https://medium.com/vizzuality-blog/tmi-dont-let-too-much-data-leave-you-in-the-dark-ecb7b206c291"
image="/images/service/blogpost/03.png"
/>
</div>
),
},
];
import usePosts from 'hooks/posts';

const BlogPosts: FC = () => {
const [slide, setSlide] = useState(1);
const { data, isFetched } = usePosts();

const posts = data?.items?.slice(0, 4); // Taking the first 4 posts
console.log(posts);

return (
<section className="relative py-12 bg-blue-600 border-t border-white/10 md:py-32">
Expand All @@ -60,42 +23,57 @@ const BlogPosts: FC = () => {
</h2>
</div>
</FadeIn>
<FadeIn>
<div className="relative h-96 blog-carousel">
<div className="absolute top-0 left-0 z-10 h-full w-96 md:bg-gradient-to-r md:from-blue-600" />
<Carousel
slide={slide}
slides={BLOGPOSTS}
autoplay={0}
options={{ circular: true, bound: false }}
onChange={(i) => {
setSlide(i);
}}
/>
<div className="absolute top-0 right-0 z-10 h-full w-96 md:bg-gradient-to-l md:from-blue-600" />
</div>
<div className="flex justify-center py-5 mt-10">
{BLOGPOSTS.map((post, i) => {
return (
<button
key={post.id}
type="button"
aria-label="line-element"
onClick={() => {
setSlide(i);
}}
className={cx({
'relative w-28 h-0.5 border border-white/20': true,
})}
>
{slide === i && (
<div className="absolute w-28 h-0.5 transform -translate-y-1/2 bg-orange-500" />
)}
</button>
);
})}
</div>
</FadeIn>
{isFetched && data && (
<>
<FadeIn>
<div className="relative h-96 blog-carousel">
<div className="absolute top-0 left-0 z-10 h-full w-96 md:bg-gradient-to-r md:from-blue-600" />
<Carousel
slide={slide}
slides={posts.map(({ guid, title, description, thumbnail }) => ({
id: guid,
content: (
<div className="mr-4">
<BlogCard
key={guid}
title={title}
description={description}
image={thumbnail}
url={guid}
/>
</div>
),
}))}
autoplay={0}
options={{ circular: true, bound: false }}
onChange={setSlide}
/>
<div className="absolute top-0 right-0 z-10 h-full w-96 md:bg-gradient-to-l md:from-blue-600" />
</div>
<div className="flex justify-center py-5 mt-10">
{posts.map((post, i) => {
return (
<button
key={post.guid}
type="button"
aria-label="line-element"
onClick={() => {
setSlide(i);
}}
className={cx({
'relative w-28 h-0.5 border border-white/20': true,
})}
>
{slide === i && (
<div className="absolute w-28 h-0.5 transform -translate-y-1/2 bg-orange-500" />
)}
</button>
);
})}
</div>
</FadeIn>
</>
)}
</div>
</section>
);
Expand Down
39 changes: 39 additions & 0 deletions marketing/src/hooks/posts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import axios from 'axios';
import { useQuery } from 'react-query';

type PostItem = {
title: string;
pubDate: string;
link: string;
guid: string;
thumbnail: string;
description: string;
content: string;
categories: string[];
};

type PostsResponse = {
status: string;
feed: {
url: string;
title: string;
link: string;
author: string;
description: string;
image: string;
};
items: PostItem[];
};

function usePosts() {
const getPosts = async () => {
const { data } = await axios.get<PostsResponse>(
'https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/@landgriffon',
);
return data;
};

return useQuery('posts', getPosts);
}

export default usePosts;

0 comments on commit 4bb4cf4

Please sign in to comment.