diff --git a/components/DemoAnimation.tsx b/components/DemoAnimation.tsx index 681680b34e5f..0e8affd76280 100644 --- a/components/DemoAnimation.tsx +++ b/components/DemoAnimation.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import Typing from 'react-typing-animation'; +import Typing from 'react-typist-component'; import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading'; @@ -43,7 +43,7 @@ export default function DemoAnimation({ className = '' }: IDemoAnimationProps) { const [showEmailDescription, setShowEmailDescription] = useState(false); const [finished, setFinished] = useState(false); const [showControls, setShowControls] = useState(false); - const typingSpeed = 60; + const typingDelay = 60; useEffect(() => { if (finished) { @@ -66,7 +66,7 @@ export default function DemoAnimation({ className = '' }: IDemoAnimationProps) { */ function renderTyping(children: React.ReactNode, callback: () => void) { return ( - } onFinishedTyping={callback}> + } onTypingDone={callback}> {children} ); @@ -100,7 +100,7 @@ export default function DemoAnimation({ className = '' }: IDemoAnimationProps) { return ( <> {common} - } onFinishedTyping={descriptionCallback}> + } onTypingDone={descriptionCallback}>
  description: This service is in charge of processing user signups :rocket: @@ -218,7 +218,7 @@ export default function DemoAnimation({ className = '' }: IDemoAnimationProps) { return ( <> {common} - } onFinishedTyping={descriptionCallback}> + } onTypingDone={descriptionCallback}>
            description: @@ -263,7 +263,7 @@ export default function DemoAnimation({ className = '' }: IDemoAnimationProps) { return ( <> {common} - } onFinishedTyping={descriptionCallback}> + } onTypingDone={descriptionCallback}>
            description: @@ -358,7 +358,8 @@ export default function DemoAnimation({ className = '' }: IDemoAnimationProps) {
-
&slash;&slash; Example
+ {/* eslint-disable-next-line react/jsx-no-comment-textnodes */} +
// Example
 
{'{'}
diff --git a/components/typography/TextLink.tsx b/components/typography/TextLink.tsx index d8d5d82c5cd5..985604c3a350 100644 --- a/components/typography/TextLink.tsx +++ b/components/typography/TextLink.tsx @@ -24,15 +24,18 @@ export default function TextLink({ href, className = '', target = '_blank', chil ); return ( - - {children} - + <> + {' '} + + {children} + + ); } diff --git a/package-lock.json b/package-lock.json index d85d1becdf5a..3c7af87781de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,6 +58,7 @@ "react-syntax-highlighter": "^15.5.0", "react-text-truncate": "^0.19.0", "react-twitter-embed": "^4.0.4", + "react-typist-component": "^1.0.6", "react-youtube-embed": "^1.0.3", "reading-time": "^1.5.0", "recharts": "^2.12.2", @@ -12649,6 +12650,14 @@ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-typist-component": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-typist-component/-/react-typist-component-1.0.6.tgz", + "integrity": "sha512-DOcMvPyqsB2dgh/DtfaDrrNSoZAFarToPXn82WN56vF9DJBeS5ss5voLI1x+nntXiWpWCUJkLL/rDS4/W0YTSQ==", + "peerDependencies": { + "react": ">=18.0.0" + } + }, "node_modules/react-youtube-embed": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/react-youtube-embed/-/react-youtube-embed-1.0.3.tgz", diff --git a/package.json b/package.json index a081c136f970..7982633c17f7 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "react-syntax-highlighter": "^15.5.0", "react-text-truncate": "^0.19.0", "react-twitter-embed": "^4.0.4", + "react-typist-component": "^1.0.6", "react-youtube-embed": "^1.0.3", "reading-time": "^1.5.0", "recharts": "^2.12.2", diff --git a/pages/[lang]/index.tsx b/pages/[lang]/index.tsx new file mode 100644 index 000000000000..20e7e90db7e3 --- /dev/null +++ b/pages/[lang]/index.tsx @@ -0,0 +1,255 @@ +import React from 'react'; + +import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading'; + +import Button from '../../components/buttons/Button'; +import GoogleCalendarButton from '../../components/buttons/GoogleCalendarButton'; +import ICSFileButton from '../../components/buttons/ICSFileButton'; +import SubscribeButton from '../../components/buttons/SubscribeButton'; +import Calendar from '../../components/Calendar'; +import Head from '../../components/Head'; +import Hero from '../../components/Hero'; +import Container from '../../components/layout/Container'; +import AdidasLogo from '../../components/logos/Adidas'; +import AxwayLogo from '../../components/logos/Axway'; +import SalesforceLogo from '../../components/logos/Salesforce'; +import SapLogo from '../../components/logos/SAP'; +import SlackLogo from '../../components/logos/Slack'; +import NewsletterSubscribe from '../../components/NewsletterSubscribe'; +import NewsroomSection from '../../components/newsroom/NewsroomSection'; +import Slack from '../../components/slack'; +import GoldSponsors from '../../components/sponsors/GoldSponsors'; +import SilverSponsors from '../../components/sponsors/SilverSponsors'; +import Sponsors from '../../components/sponsors/Sponsors'; +import SupportUs from '../../components/SupportUs/SupportUs'; +import Testimonial from '../../components/Testimonial'; +import Heading from '../../components/typography/Heading'; +import Paragraph from '../../components/typography/Paragraph'; +import TextLink from '../../components/typography/TextLink'; +import { getAllLanguageSlugs, getLanguage, useTranslation } from '../../utils/i18n'; + +/** + * @description The HomePage is the landing page of the website. + */ +export default function HomePage() { + const { t } = useTranslation('landing-page'); + + return ( + <> + +
+ + + + + + + {t('adopters.title')} + + + {t('adopters.description')} + + {t('adopters.linkText')} + + +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ +
+ + + +
+ + + + {t('community.title')} + + {t('community.subtitle')} +
+ +
+
+ +
+
+
+ + {t('community.slackCTATitle')} + + {t('community.slackCTADesc')} +
+
+
+
+
+ +
+
+ +
+
+
+ + {t('community.meetingTitle')} + + + {t('community.meetingDesc')} + + {t('community.meetingLink')} + +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+
+ + + +
+
+ +
+ + + {t('sponsors.platinumTitle')} + + + + + + + {t('sponsors.goldTitle')} + + + + + + + {t('sponsors.silverTitle')} + + + + + + + {t('sponsors.sponsorCTATitle')} + + + {t('sponsors.sponsorCTADesc')} + + {t('sponsors.sponsorCTALink')} + + + +
+ + + {t('sponsors.supportedByTitle')} + + + {t('sponsors.supportedByPretext')} + + {t('sponsors.supportedByLink')} + {' '} + {t('sponsors.supportedByPosttext')} + + + + + + {t('testimonials.title')} + +
    + + + + +
+
+
+ + ); +} + +/** + * @description This function generates all language slugs for the landing page. + * @returns {object} The paths object containing all language slugs. + */ +export async function getStaticPaths() { + const paths = getAllLanguageSlugs(); + + return { + paths, + fallback: false + }; +} + +/** + * @description This function fetches the language content for the landing page. + * @param {object} params The language parameter. + * @returns {object} The language content for the landing page. + */ +export async function getStaticProps({ params }: any) { + const language = getLanguage(params.lang); + + return { + props: { + language + } + }; +} diff --git a/pages/index.tsx b/pages/index.tsx index 9a3795294426..348311a7aa2a 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,54 +1,24 @@ -import { Inter } from 'next/font/google'; +import { languageDetection } from '@/utils/i18n'; -import AlgoliaSearch, { SearchButton } from '@/components/AlgoliaSearch'; -import Button from '@/components/buttons/Button'; -import IconArrowRight from '@/components/icons/ArrowRight'; -import IconLoupe from '@/components/icons/Loupe'; - -import { useTranslation } from '../utils/i18n'; - -const inter = Inter({ subsets: ['latin'] }); +import Head from '../components/Head'; /** - * @description The Home component is the main page of the application. + * @description This is the home page which is the first page that loads when the user visits the website. */ -export default function Home() { - const { t } = useTranslation('landing-page'); +export default function HomePage() { + const loader: string = 'img/loaders/loader.png'; // preloader image for the tools + + languageDetection(); return ( -
-
-
+ ); } diff --git a/tsconfig.json b/tsconfig.json index 57d570ff80d7..d7c7683d9403 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,6 @@ "@/*": ["./*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types/**/*.d.ts"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types/**/*.d.ts", "**/*.json"], "exclude": ["node_modules", "netlify"] } diff --git a/utils/api.ts b/utils/api.ts index d7a35af5073a..bbeef4bcf1b9 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -15,22 +15,19 @@ export function getAllPosts(): IPosts { * @param {string} [type=''] - The type of the post. * @returns {Object | undefined} The post if found, undefined otherwise. */ -export function getPostBySlug( - slug: string, - type: string = '' -) { - if(type) - return (posts as any)[type].find((post: IPost) => post.slug === slug && !post.isSection ) - else { - let item; - Object.entries(posts).forEach(([key, value]) => { - let content - if(key!== 'docsTree') - content = (posts as any)[key].find((post: IPost) => post.slug === slug && !post.isSection) - if(content) item = content - }) - return item - } +export function getPostBySlug(slug: string, type: string = '') { + if (type) return (posts as any)[type].find((post: IPost) => post.slug === slug && !post.isSection); + + let item; + + Object.entries(posts).forEach(([key]) => { + let content; + + if (key !== 'docsTree') content = (posts as any)[key].find((post: IPost) => post.slug === slug && !post.isSection); + if (content) item = content; + }); + + return item; } /** @@ -39,11 +36,6 @@ export function getPostBySlug( * @param {string} slug - The slug of the document. * @returns {Object | undefined} The document if found, undefined otherwise. */ -export function getDocBySlug( - structuredPosts: IPost[], - slug: string -): object | undefined { - return structuredPosts.find( - (post) => post.slug === slug && !post.isSection - ); +export function getDocBySlug(structuredPosts: IPost[], slug: string): object | undefined { + return structuredPosts.find((post) => post.slug === slug && !post.isSection); } diff --git a/utils/staticHelpers.js b/utils/staticHelpers.js deleted file mode 100644 index 3dab218265b6..000000000000 --- a/utils/staticHelpers.js +++ /dev/null @@ -1,204 +0,0 @@ -import { getPostBySlug, getAllPosts } from './api'; -import moment from 'moment'; - -export function getStaticPropsHelper(path) { - return async function getStaticProps({ params }) { - const navItems = [ - { - title: 'Getting started', - slug: 'docs/getting-started', - items: getSectionItems('docs/getting-started'), - }, - { - title: 'Tutorials', - slug: 'docs/tutorials', - items: getSectionItems('docs/tutorials'), - }, - ]; - const post = getPostBySlug( - path, - params && params.slug ? params.slug : 'index', - [ - 'title', - 'date', - 'slug', - 'fullSlug', - 'author', - 'content', - 'ogImage', - 'coverImage', - ] - ); - const content = post.content || ''; - - return { - props: { - post: { - ...post, - content, - }, - navItems, - }, - }; - }; -} - -function getSectionItems(path) { - return getAllPosts(path, ['slug', 'fullSlug', 'title', 'weight']).sort( - (p1, p2) => (p1.weight || 0) - (p2.weight || 0) - ); -} - -export function getStaticPathsHelper(path) { - return async function getStaticPaths() { - const posts = getAllPosts(path, ['slug']); - - return { - paths: posts.map((post) => { - return { - params: { - slug: post.slug, - }, - }; - }), - fallback: false, - }; - }; -} - -export function getEvents(events, size) { - let meetingsWithDates = events.map((event) => ({ - ...event, - date: moment(event.date), - })); - meetingsWithDates.sort((a, b) => a.date - b.date); - if (size) { - return meetingsWithDates - .filter((meeting) => meeting.date > new Date()) - .slice(0, size || meetingsWithDates.length); - } - const sortedMeetings = []; - meetingsWithDates.filter((a) => { - if (a.date > new Date()) { - sortedMeetings.push(a); - } - }); - meetingsWithDates.sort((a, b) => { - return b.date - a.date - }) - meetingsWithDates.filter((a) => { - if (a.date < new Date()) { - sortedMeetings.push(a); - } - }); - - meetingsWithDates = sortedMeetings - - return meetingsWithDates; -} - -export const generateCaseStudyContent = (data) => { - const { challenges, solution, usecase, architecture, testing, codegen, schemaStorage, registry, versioning, validation, asyncapiStorage, asyncapiEditing, asyncapiExtensions, asyncapiDocumentation, asyncapiBindings, asyncapiTools, additionalResources, casestudy } = data; - const languages= casestudy.technical.languages - const frameworks=casestudy.technical.frameworks - const protocols=casestudy.technical.protocols - const versions=casestudy.asyncapi.versions - - return [ - { - title: "Challenges", - content: challenges, - }, - { - title: "Solution", - content: solution, - }, - { - title: "Use Case", - content: usecase, - }, - { - title: "More Details", - items: [ - `Languages: ${languages.join(", ")}`, - `Frameworks: ${frameworks.join(", ")}`, - `Protocols: ${protocols.join(", ")}`, - ], - children: [ - { - title: "Testing strategy", - content: testing, - }, - { - title: "Approach to code generation", - content: codegen, - }, - { - title: "Architecture", - content: architecture, - }, - { - title: "More Details about AsyncAPI", - items: [ - `Version: ${versions.join(", ")}`, - `Who maintains documents: ${casestudy.asyncapi.maintainers}}`, - `Internal users: ${casestudy.asyncapi.audience.internal.toString()}`, - `External users: ${casestudy.asyncapi.audience.external.toString()}`, - ], - children: [ - { - title: "How AsyncAPI documents are stored", - content: asyncapiStorage, - }, - { - title: "Where maintainers edit AsyncAPI documents", - content: asyncapiEditing, - }, - { - title: "What extensions are used", - content: asyncapiExtensions, - }, - { - title: "How documentation is generated", - content: asyncapiDocumentation, - }, - { - title: "What bindings are used", - content: asyncapiBindings, - }, - { - title: "What tools are used", - content: asyncapiTools, - }, - ], - }, - { - title: "Schemas", - items: [`Spec: ${casestudy.schemas.description}`], - children: [ - { - title: "Storage strategy", - content: schemaStorage, - }, - { - title: "Schema Registry", - content: registry, - }, - { - title: "Versioning of schemas", - content: versioning, - }, - { - title: "Validation of message schemas", - content: validation, - }, - { - title: "Additional Resources", - content: additionalResources, - }, - ], - }, - ], - }, - ]; -} \ No newline at end of file diff --git a/utils/staticHelpers.ts b/utils/staticHelpers.ts new file mode 100644 index 000000000000..230f26da6ee0 --- /dev/null +++ b/utils/staticHelpers.ts @@ -0,0 +1,171 @@ +import moment from 'moment'; + +import type { IEvent } from '@/types/event'; + +/** + * Retrieves events sorted by date. + * @param {IEvent[]} events - The list of events to retrieve. + * @param {number} [size] - The optional maximum number of events to return. + * @returns {any[]} The sorted list of events. + */ +export function getEvents(events: IEvent[], size?: number) { + let meetingsWithDates: any = events.map((event) => ({ + ...event, + date: moment(event.date) + })); + + meetingsWithDates.sort((a: any, b: any) => a.date - b.date); + + if (size) { + return meetingsWithDates + .filter((meeting: any) => meeting.date > moment(new Date().toDateString())) + .slice(0, size || meetingsWithDates.length); + } + + const sortedMeetings: any = []; + + for (const meeting of meetingsWithDates) { + if (meeting.date > moment(new Date().toDateString())) { + sortedMeetings.push(meeting); + } + } + + meetingsWithDates.sort((a: any, b: any) => { + return b.date - a.date; + }); + + for (const meeting of meetingsWithDates) { + if (meeting.date < moment(new Date().toDateString())) { + sortedMeetings.push(meeting); + } + } + + meetingsWithDates = sortedMeetings; + + return meetingsWithDates; +} + +export const generateCaseStudyContent = (data: any) => { + const { + challenges, + solution, + usecase, + architecture, + testing, + codegen, + schemaStorage, + registry, + versioning, + validation, + asyncapiStorage, + asyncapiEditing, + asyncapiExtensions, + asyncapiDocumentation, + asyncapiBindings, + asyncapiTools, + additionalResources, + casestudy + } = data; + const { languages } = casestudy.technical; + const { frameworks } = casestudy.technical; + const { protocols } = casestudy.technical; + const { versions } = casestudy.asyncapi; + + return [ + { + title: 'Challenges', + content: challenges + }, + { + title: 'Solution', + content: solution + }, + { + title: 'Use Case', + content: usecase + }, + { + title: 'More Details', + items: [ + `Languages: ${languages.join(', ')}`, + `Frameworks: ${frameworks.join(', ')}`, + `Protocols: ${protocols.join(', ')}` + ], + children: [ + { + title: 'Testing strategy', + content: testing + }, + { + title: 'Approach to code generation', + content: codegen + }, + { + title: 'Architecture', + content: architecture + }, + { + title: 'More Details about AsyncAPI', + items: [ + `Version: ${versions.join(', ')}`, + `Who maintains documents: ${casestudy.asyncapi.maintainers}`, + `Internal users: ${casestudy.asyncapi.audience.internal.toString()}`, + `External users: ${casestudy.asyncapi.audience.external.toString()}` + ], + children: [ + { + title: 'How AsyncAPI documents are stored', + content: asyncapiStorage + }, + { + title: 'Where maintainers edit AsyncAPI documents', + content: asyncapiEditing + }, + { + title: 'What extensions are used', + content: asyncapiExtensions + }, + { + title: 'How documentation is generated', + content: asyncapiDocumentation + }, + { + title: 'What bindings are used', + content: asyncapiBindings + }, + { + title: 'What tools are used', + content: asyncapiTools + } + ] + }, + { + title: 'Schemas', + items: [`Spec: ${casestudy.schemas.description}`], + children: [ + { + title: 'Storage strategy', + content: schemaStorage + }, + { + title: 'Schema Registry', + content: registry + }, + { + title: 'Versioning of schemas', + content: versioning + }, + { + title: 'Validation of message schemas', + content: validation + }, + { + title: 'Additional Resources', + content: additionalResources + } + ] + } + ] + } + ]; +};