Skip to content

Commit

Permalink
migrate newsroom components
Browse files Browse the repository at this point in the history
Signed-off-by: Ansh Goyal <[email protected]>
  • Loading branch information
anshgoyalevil committed Mar 4, 2024
1 parent 32ecd60 commit 48190fe
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 2 deletions.
4 changes: 2 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"max-len": [
"error",
{
"code": 120,
"code": 240,
"ignoreUrls": true,
"ignorePattern": "*className=([\\s\\S]*?)*" // Ignore classnames
}
Expand Down Expand Up @@ -186,7 +186,7 @@
"max-len": [
"error",
{
"code": 120
"code": 240
}
],
"max-lines": [
Expand Down
41 changes: 41 additions & 0 deletions components/AuthorAvatars.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';

interface Author {
name: string;
photo: string;
link?: string;
}

interface AuthorAvatarsProps {
authors: Author[];
}

const AuthorAvatars: React.FC<AuthorAvatarsProps> = ({ authors = [] }) => {
return (
<>
{authors.map((author, index) => {
const avatar = (
<img
key={index}
title={author.name}
className={`${index > 0 ? `left- absolute${index * 7} top-0` : `mr- relative${(authors.length - 1) * 7}`} z-${(authors.length - 1 - index) * 10} size-10 rounded-full border-2 border-white object-cover hover:z-50`}
src={author.photo}
loading='lazy'
data-testid='AuthorAvatars-img'
alt={author.name} // Added alt attribute here
/>
);

return author.link ? (
<a href={author.link} key={index} data-testid='AuthorAvatars-link'>
{avatar}
</a>
) : (
<React.Fragment key={index}>{avatar}</React.Fragment>
);
})}
</>
);
};

export default AuthorAvatars;
141 changes: 141 additions & 0 deletions components/navigation/BlogPostItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import moment from 'moment';
import Link from 'next/link';
import type { Ref } from 'react';
import { forwardRef } from 'react';
import TextTruncate from 'react-text-truncate';

import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

import AuthorAvatars from '../AuthorAvatars';
import Heading from '../typography/Heading';
import Paragraph from '../typography/Paragraph';

interface Author {
name: string;
photo: string;
link?: string;
}

interface Post {
type: string;
alt?: string;
slug: string;
cover: string;
title: string;
excerpt: string;
authors: Author[];
date: string;
readingTime: number;
}

interface Props {
post: Post;
className?: string;
id?: string;
}

const BlogPostItem = forwardRef(function BlogPostItem(
{ post, className = '', id = '' }: Props,
ref: Ref<HTMLLIElement>
) {
let typeColors: [string, string] = ['bg-indigo-100', 'text-indigo-800'];

switch (post.type.toLowerCase()) {
case 'video':
typeColors = ['bg-pink-100', 'text-pink-800'];
break;
case 'marketing':
typeColors = ['bg-orange-100', 'text-orange-800'];
break;
case 'strategy':
typeColors = ['bg-green-100', 'text-green-800'];
break;
case 'communication':
typeColors = ['bg-teal-100', 'text-teal-800'];
break;
default:
}

return (
<li className={`rounded-lg ${className}`} ref={ref} id={id}>
<article className='h-full rounded-lg'>
<Link href={post.slug} passHref>
<a
className={
'flex h-full cursor-pointer flex-col divide-y divide-gray-200 overflow-hidden rounded-lg border border-gray-200 shadow-md transition-all duration-300 ease-in-out hover:shadow-lg'
}
data-testid='BlogPostItem-Link'
>
<img
className='h-48 w-full object-cover'
src={post.cover}
alt=''
loading='lazy'
data-testid='BlogPostItem-Img'
/>
<div className='flex flex-1 flex-col justify-between bg-white p-6'>
<div className='flex-1'>
<Paragraph typeStyle={ParagraphTypeStyle.sm} textColor='text-indigo-500'>
<span
className={`inline-flex items-center rounded-full px-3 py-0.5 ${typeColors[0]} ${typeColors[1]}`}
>
{post.type}
</span>
</Paragraph>
<Link href={post.slug}>
<a className='block'>
<Heading level={HeadingLevel.h5} typeStyle={HeadingTypeStyle.smSemibold} className='mt-2'>
{post.title}
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.sm} className='mt-3'>
<TextTruncate element='span' line={4} text={post.excerpt} />
</Paragraph>
</a>
</Link>
</div>
<div className='mt-6 flex items-center'>
<div className='relative shrink-0'>
<AuthorAvatars authors={post.authors} />
</div>
<div className='ml-3'>
<Heading level={HeadingLevel.h3} typeStyle={HeadingTypeStyle.xsSemibold} textColor='text-gray-900'>
<span className='hover:underline'>
{post.authors
.map((author, index) =>
author.link ? (
<a
key={index}
data-alt={author.name}
href={author.link}
onClick={(e) => {
e.stopPropagation();
}}
target='_blank'
rel='noreferrer'
>
{author.name}
</a>
) : (
author.name
)
)
.reduce((prev, curr) => [prev, ' & ', curr].join(''))}
</span>
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.sm} className='flex'>
<time dateTime={post.date}>{moment(post.date).format('MMMM D, YYYY')}</time>
<span className='mx-1'>&middot;</span>
<span>{post.readingTime} min read</span>
</Paragraph>
</div>
</div>
</div>
</a>
</Link>
</article>
</li>
);
});

export default BlogPostItem;
43 changes: 43 additions & 0 deletions components/newsroom/NewsroomArticle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';

import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

import articlesData from '../../config/articles.json';
import Heading from '../typography/Heading';
import Paragraph from '../typography/Paragraph';

interface Article {
url: string;
publishDate: string;
title: string;
}

const NewsroomArticle: React.FC = () => {
return (
<ul className='flex w-full flex-col gap-2 px-2 pb-4'>
{articlesData.map((article: Article, index: number) => (
<li key={index}>
<a
className='mb-2 block rounded-md border border-gray-200 bg-white p-6 text-left shadow-md transition-all duration-300 ease-in-out hover:shadow-lg lg:w-full'
href={article.url}
target='_blank'
rel='noopener noreferrer'
data-testid={`NewsroomArticle-${index}`}
>
<div>
<Paragraph typeStyle={ParagraphTypeStyle.sm} textColor='text-gray-600'>
{article.publishDate}
</Paragraph>
<Heading level={HeadingLevel.h4} typeStyle={HeadingTypeStyle.xsSemibold} className='mt-3'>
{article.title}
</Heading>
</div>
</a>
</li>
))}
</ul>
);
};

export default NewsroomArticle;
59 changes: 59 additions & 0 deletions components/newsroom/YouTubeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';

import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

import ArrowRight from '../icons/ArrowRight';
import Heading from '../typography/Heading';
import Paragraph from '../typography/Paragraph';
import TextLink from '../typography/TextLink';

interface YouTubeVideo {
image_url: string;
title: string;
description: string;
videoId: string;
}

interface Props {
video: YouTubeVideo;
}

const YouTubeCard: React.FC<Props> = ({ video }) => {
return (
<li className={'min-w-full h-full max-w-md rounded-lg px-2 pb-6'}>
<article className='h-full rounded-lg'>
<div className={'flex h-full cursor-pointer flex-col divide-y divide-gray-200 overflow-hidden rounded-lg border border-gray-200 shadow-md transition-all duration-300 ease-in-out hover:shadow-lg'}>
<img data-testid='YoutubeCard-img'
src={video.image_url}
alt='video'
className='h-60 w-full object-cover'
/>

<div className='flex flex-1 flex-col justify-between bg-white p-6' data-testid='YoutubeCard-main'>
<div>
<Heading level={HeadingLevel.h3} typeStyle={HeadingTypeStyle.smSemibold} className='mt-2'>
{video.title}
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mt-3 break-words'>
{video.description}
</Paragraph>
</div>

<div className='mt-6 block'>
<TextLink
href={`https://youtube.com/watch?v=${video.videoId}`}
target='_blank'
>
Watch on Youtube
<ArrowRight className='inline w-6' />
</TextLink>
</div>
</div>
</div>
</article>
</li>
);
};

export default YouTubeCard;
38 changes: 38 additions & 0 deletions components/newsroom/swiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useEffect, useRef, useState } from 'react';

/**
* Custom hook to manage swiper reference.
* @returns A tuple containing the wrapper element and a ref object.
*/
export function useSwiperRef(): [HTMLDivElement | null, React.RefObject<HTMLDivElement>] {
const [wrapper, setWrapper] = useState<HTMLDivElement | null>(null);
const ref = useRef<HTMLDivElement>(null);

// useEffect hook to set the wrapper element to the ref's current value once it's available.
useEffect(() => {
if (ref.current) {
setWrapper(ref.current);
}
}, []);

return [wrapper, ref];
}

/**
* Function to check if the current index is the last snap index based on the viewport width.
* @param {number} current - The current index.
* @returns {boolean} Whether the current index is the last snap index.
*/
export function checkLastSnapIndex(current: number): boolean {
if (typeof window === 'undefined') {
return false;
}

const viewportWidth = document.documentElement.clientWidth;

if (viewportWidth <= 640) {
return current === 4;
}

return current === 3;
}
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"@types/node": "^20",
"@types/react": "^18.0.1",
"@types/react-dom": "^18",
"@types/react-text-truncate": "^0.14.4",
"@typescript-eslint/eslint-plugin": "^6.19.1",
"@typescript-eslint/parser": "^6.19.1",
"dedent": "^1.5.1",
Expand Down

0 comments on commit 48190fe

Please sign in to comment.