-
-
Notifications
You must be signed in to change notification settings - Fork 637
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: migrate layout and campaigns (#2743)
Co-authored-by: Akshat Nema <[email protected]>%0ACo-authored-by: akshatnema <[email protected]>%0ACo-authored-by: aks-nema <[email protected]>%0ACo-authored-by: Ansh Goyal <[email protected]>
- Loading branch information
1 parent
6760c9d
commit ce3446d
Showing
23 changed files
with
1,021 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import Head from 'next/head'; | ||
import { useContext } from 'react'; | ||
import ReactGA from 'react-ga'; | ||
import TagManager from 'react-gtm-module'; | ||
|
||
import AppContext from '../context/AppContext'; | ||
|
||
interface IHeadProps { | ||
title: string; | ||
description?: string; | ||
image: string; | ||
rssTitle?: string; | ||
rssLink?: string; | ||
} | ||
|
||
/** | ||
* @param {string} props.title - The title of the page | ||
* @param {string} props.description - The description of the page | ||
* @param {string} props.image - The image of the page | ||
* @param {string} props.rssTitle - The RSS title of the page | ||
* @param {string} props.rssLink - The RSS link of the page | ||
* @description The head of the page with the meta tags | ||
*/ | ||
export default function HeadComponent({ | ||
title, | ||
description = `Open source tools to easily build and maintain your event-driven architecture. | ||
All powered by the AsyncAPI specification, the industry standard for defining asynchronous APIs.`, | ||
image = '/img/social/website-card.jpg', | ||
rssTitle = 'RSS Feed for AsyncAPI Initiative Blog', | ||
rssLink = '/rss.xml' | ||
}: IHeadProps) { | ||
const url = process.env.DEPLOY_PRIME_URL || process.env.DEPLOY_URL || 'http://localhost:3000'; | ||
const appContext = useContext(AppContext); | ||
const { path = '' } = appContext || {}; | ||
let currImage = image; | ||
|
||
const permalink = `${url}${path}`; | ||
let type = 'website'; | ||
|
||
if (path.startsWith('/docs') || path.startsWith('/blog')) { | ||
type = 'article'; | ||
} | ||
|
||
if (!image.startsWith('http') && !image.startsWith('https')) { | ||
currImage = `${url}${image}`; | ||
} | ||
|
||
const permTitle = 'AsyncAPI Initiative for event-driven APIs'; | ||
|
||
const currTitle = title ? `${title} | ${permTitle}` : permTitle; | ||
|
||
// enable google analytics | ||
if (typeof window !== 'undefined' && window.location.hostname.includes('asyncapi.com')) { | ||
TagManager.initialize({ gtmId: 'GTM-T58BTVQ' }); | ||
ReactGA.initialize('UA-109278936-1'); | ||
ReactGA.pageview(window.location.pathname + window.location.search); | ||
} | ||
|
||
return ( | ||
<Head> | ||
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no' /> | ||
<meta httpEquiv='x-ua-compatible' content='ie=edge' /> | ||
<meta httpEquiv='Content-Type' content='text/html; charset=utf-8' /> | ||
<meta name='description' content={description} /> | ||
<link rel='alternate' type='application/rss+xml' title={rssTitle} href={rssLink} /> | ||
|
||
{/* Google / Search Engine Tags */} | ||
<meta itemProp='name' content={title} /> | ||
<meta itemProp='description' content={description} /> | ||
<meta itemProp='image' content={currImage} /> | ||
|
||
{/* Twitter Card data */} | ||
<meta name='twitter:card' content='summary_large_image' /> | ||
<meta name='twitter:title' content={title} /> | ||
<meta name='twitter:description' content={description} /> | ||
<meta name='twitter:image' content={currImage} /> | ||
|
||
{/* Open Graph data */} | ||
<meta property='og:title' content={title} /> | ||
<meta property='og:type' content={type} /> | ||
<meta property='og:url' content={permalink} /> | ||
<meta property='og:image' content={currImage} /> | ||
<meta property='og:description' content={description} /> | ||
|
||
<title>{currTitle}</title> | ||
</Head> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { useState } from 'react'; | ||
import Scrollspy from 'react-scrollspy'; | ||
import { twMerge } from 'tailwind-merge'; | ||
|
||
import ArrowRight from './icons/ArrowRight'; | ||
|
||
interface ITOCProps { | ||
className?: string; | ||
cssBreakingPoint?: string; | ||
toc: { | ||
lvl: number; | ||
content: string; | ||
slug: string; | ||
}[]; | ||
contentSelector?: string; | ||
depth?: number; | ||
} | ||
|
||
/** | ||
* @description The table of contents | ||
* @param {string} props.className - The class name of the component | ||
* @param {string} props.cssBreakingPoint - The CSS breaking point | ||
* @param {Array} props.toc - The table of contents | ||
* @param {string} props.contentSelector - The content selector | ||
* @param {number} props.depth - The depth of the table of contents | ||
*/ | ||
export default function TOC({ className, cssBreakingPoint = 'xl', toc, contentSelector, depth = 2 }: ITOCProps) { | ||
const [open, setOpen] = useState(false); | ||
|
||
if (!toc || !toc.length) return null; | ||
const minLevel = toc.reduce((mLevel, item) => (!mLevel || item.lvl < mLevel ? item.lvl : mLevel), 0); | ||
const tocItems = toc | ||
.filter((item) => item.lvl <= minLevel + depth) | ||
.map((item) => ({ | ||
...item, | ||
content: item.content.replace(/[\s]?\{#[\w\d\-_]+\}$/, '').replace(/(<([^>]+)>)/gi, ''), | ||
// For TOC rendering in specification files in the spec repo we have "a" tags added manually to the spec | ||
// markdown document MDX takes these "a" tags and uses them to render the "id" for headers like | ||
// a-namedefinitionsapplicationaapplication slugWithATag contains transformed heading name that is later used | ||
// for scroll spy identification | ||
slugWithATag: item.content | ||
.replace(/[<>?!:`'."\\/=]/gi, '') | ||
.replace(/\s/gi, '-') | ||
.toLowerCase() | ||
})); | ||
|
||
return ( | ||
<div | ||
className={twMerge(`${className} ${tocItems.length ? '' : 'hidden'} | ||
${cssBreakingPoint === 'xl' ? 'xl:block' : 'lg:block'} md:top-24 md:max-h-(screen-14) z-20`)} | ||
onClick={() => setOpen(!open)} | ||
> | ||
<div | ||
className={`flex cursor-pointer ${tocItems.length ? '' : 'hidden'} | ||
${cssBreakingPoint === 'xl' ? 'xl:cursor-auto' : 'lg:cursor-auto'} xl:mt-2`} | ||
> | ||
<h5 | ||
className={twMerge(`${open && 'mb-4'} flex-1 text-primary-500 font-medium uppercase tracking-wide | ||
text-sm font-sans antialiased ${ | ||
cssBreakingPoint === 'xl' | ||
? `xl:mb-4 xl:text-xs xl:text-gray-900 | ||
xl:font-bold` | ||
: 'lg:mb-4 lg:text-xs lg:text-gray-900 lg:font-bold' | ||
}`)} | ||
data-testid='TOC-Heading' | ||
> | ||
On this page | ||
</h5> | ||
<div className={`text-underline p4 text-center ${cssBreakingPoint === 'xl' ? 'xl:hidden' : 'lg:hidden'}`}> | ||
<ArrowRight | ||
className={`${open ? '-rotate-90' : 'rotate-90'} -mt-0.5 h-6 | ||
text-primary-500 transition duration-200 ease-in-out`} | ||
/> | ||
</div> | ||
</div> | ||
<div className={`${!open && 'hidden'} ${cssBreakingPoint === 'xl' ? 'xl:block' : 'lg:block'}`}> | ||
<Scrollspy | ||
items={tocItems.map((item) => item.slug)} | ||
currentClassName='text-primary-500 font-bold' | ||
componentTag='div' | ||
rootEl={contentSelector} | ||
offset={-120} | ||
> | ||
{tocItems.map((item, index) => ( | ||
<a | ||
className={`pl-${2 ** (item.lvl - 1)} font-normal mb-1 block font-sans text-sm | ||
text-gray-900 antialiased transition duration-100 ease-in-out hover:underline`} | ||
href={`#${item.slug}`} | ||
key={index} | ||
data-testid='TOC-Link' | ||
> | ||
{item.content.replaceAll('`', '')} | ||
</a> | ||
))} | ||
</Scrollspy> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import React from 'react'; | ||
|
||
import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading'; | ||
import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; | ||
|
||
import Button from '../buttons/Button'; | ||
import Heading from '../typography/Heading'; | ||
import Paragraph from '../typography/Paragraph'; | ||
import AnnouncementRemainingDays from './AnnouncementRemainingDays'; | ||
|
||
interface BannerProps { | ||
title: string; | ||
dateLocation: string; | ||
cfaText: string; | ||
eventName: string; | ||
cfpDeadline: string; | ||
link: string; | ||
city: string; | ||
activeBanner: boolean; | ||
small: boolean; | ||
className: string; | ||
} | ||
|
||
/** | ||
* @description The banner to use for Announcement | ||
* @param {string} props.title - The title of the banner | ||
* @param {string} props.dateLocation - The date and location of the banner | ||
* @param {string} props.cfaText - The call for action text | ||
* @param {string} props.eventName - The name of the event | ||
* @param {string} props.cfpDeadline - The deadline for the call for speakers | ||
* @param {string} props.link - The link of the banner | ||
* @param {string} props.city - The city of the banner | ||
* @param {Boolean} props.activeBanner - Whether the banner is active | ||
* @param {Boolean} props.small - Whether the banner is small | ||
* @param {string} props.className - The class name of the banner | ||
*/ | ||
export default function Banner({ | ||
title, | ||
dateLocation, | ||
cfaText, | ||
eventName, | ||
cfpDeadline, | ||
link, | ||
city, | ||
activeBanner, | ||
small, | ||
className | ||
}: BannerProps) { | ||
return ( | ||
<div | ||
className={`absolute size-full rounded border border-gray-200 bg-gray-50 py-6 | ||
transition-transform${className} ${small ? 'mb-4' : 'mx-3 mb-6 mt-3 p-3'} | ||
${activeBanner ? 'z-10 scale-100 opacity-100' : 'z-0 scale-90 opacity-0'}`} | ||
data-testid='AnnouncementHero-main-div' | ||
> | ||
<Heading className='countdown-text-gradient' level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.lg}> | ||
{title} | ||
</Heading> | ||
<Heading className='countdown-text-gradient' level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.md}> | ||
{city} | ||
</Heading> | ||
<Paragraph typeStyle={ParagraphTypeStyle.lg}>{dateLocation}</Paragraph> | ||
<AnnouncementRemainingDays dateTime={cfpDeadline} eventName={eventName} /> | ||
<div className='mt-6 space-x-2 pb-2'> | ||
<Button href={link} target='_blank' text={cfaText} data-testid='AnnouncementHero-submit-session' /> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
import ArrowLeft from '../icons/ArrowLeft'; | ||
import ArrowRight from '../icons/ArrowRight'; | ||
import Container from '../layout/Container'; | ||
import Banner from './AnnouncementBanner'; | ||
import { banners } from './banners'; | ||
|
||
interface IAnnouncementHeroProps { | ||
className?: string; | ||
small?: boolean; | ||
} | ||
|
||
/** | ||
* @param {string} props.className - The class name of the announcement hero | ||
* @param {Boolean} props.small - Whether the banner is small | ||
* @param {Boolean} props.hideVideo - Whether the video should be hidden | ||
* @description The announcement hero | ||
*/ | ||
export default function AnnouncementHero({ className = '', small = false }: IAnnouncementHeroProps) { | ||
const [activeIndex, setActiveIndex] = useState(0); | ||
|
||
const len = banners.length; | ||
|
||
const goToPrevious = () => { | ||
setActiveIndex((prevIndex) => (prevIndex === 0 ? len - 1 : prevIndex - 1)); | ||
}; | ||
|
||
const goToNext = () => { | ||
setActiveIndex((prevIndex) => (prevIndex === len - 1 ? 0 : prevIndex + 1)); | ||
}; | ||
|
||
const goToIndex = (index: number) => { | ||
setActiveIndex(index); | ||
}; | ||
|
||
useEffect(() => { | ||
const interval = setInterval(() => setActiveIndex((index) => index + 1), 5000); | ||
|
||
return () => { | ||
clearInterval(interval); | ||
}; | ||
}, [activeIndex]); | ||
|
||
return ( | ||
<Container as='section' padding='' className={'text-center'}> | ||
<div className='relative flex flex-row items-center justify-center overflow-x-hidden md:gap-4'> | ||
<div | ||
className={`absolute left-0 top-1/2 z-10 mb-2 flex size-8 -translate-y-1/2 cursor-pointer | ||
items-center justify-center rounded-full bg-primary-500 opacity-50 hover:bg-primary-600 md:opacity-100`} | ||
onClick={goToPrevious} | ||
> | ||
<ArrowLeft className='w-4 text-white' /> | ||
</div> | ||
<div className='relative flex w-5/6 flex-col items-center justify-center gap-2 pr-3'> | ||
<div className='relative h-72 w-full overflow-hidden lg:h-[17rem] lg:w-[38rem]'> | ||
{banners.map( | ||
(banner, index) => | ||
banner.show && ( | ||
<Banner | ||
key={index} | ||
title={banner.title} | ||
dateLocation={banner.dateLocation} | ||
cfaText={banner.cfaText} | ||
eventName={banner.eventName} | ||
cfpDeadline={banner.cfpDeadline} | ||
link={banner.link} | ||
city={banner.city} | ||
activeBanner={index === activeIndex % len} | ||
className={className} | ||
small={small} | ||
/> | ||
) | ||
)} | ||
</div> | ||
<div className='m-auto flex justify-center'> | ||
{banners.map((banner, index) => ( | ||
<div | ||
key={index} | ||
className={`mx-1 size-2 cursor-pointer rounded-full ${ | ||
activeIndex % len === index ? 'bg-primary-500' : 'bg-gray-300' | ||
}`} | ||
onClick={() => goToIndex(index)} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
<div | ||
className={`absolute right-0 top-1/2 z-10 mb-2 size-8 -translate-y-1/2 cursor-pointer | ||
rounded-full bg-primary-500 opacity-50 hover:bg-primary-600 md:opacity-100`} | ||
onClick={goToNext} | ||
> | ||
<ArrowRight className='text-white' /> | ||
</div> | ||
</div> | ||
</Container> | ||
); | ||
} |
Oops, something went wrong.