diff --git a/.eslintrc b/.eslintrc index bf605da6d4f..1ad216dd1bb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,6 +5,11 @@ "eslint:recommended", "plugin:prettier/recommended" ], + "env": { + "browser": true, + "es2021": true, + "node": true + }, "plugins": [ "react", "jsx-a11y" @@ -16,8 +21,22 @@ "singleQuote": true, "endOfLine": "auto" } + ], + "max-len": [ + "error", + { + "code": 120, + "ignoreUrls": true, + "ignorePattern": "*className=([\\s\\S]*?)*" // Ignore classnames + } ] }, + "globals": { + "React": true, + "expect": true, + "jsdom": true, + "JSX": true + }, "overrides": [ // Configuration for TypeScript files { diff --git a/.prettierrc.json b/.prettierrc.json index a77f4587b0b..364b2d386b0 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -2,5 +2,6 @@ "singleQuote": true, "jsxSingleQuote": true, "arrowParens": "always", - "trailingComma": "es5" + "trailingComma": "es5", + "printWidth": 120 } diff --git a/components/buttons/Button.tsx b/components/buttons/Button.tsx new file mode 100644 index 00000000000..d3892ea2866 --- /dev/null +++ b/components/buttons/Button.tsx @@ -0,0 +1,93 @@ +import Link from 'next/link'; +import { twMerge } from 'tailwind-merge'; + +type IButtonProps = { + text: string; + icon?: React.ReactNode; + iconPosition?: 'left' | 'right'; + target?: string; + bgClassName?: string; + textClassName?: string; + buttonSize?: 'small' | 'default'; + type?: 'submit' | 'reset' | 'button'; +} & ( + | ({ + href: string; + } & React.AnchorHTMLAttributes) + | ({ + href?: undefined | null; + } & React.ButtonHTMLAttributes) +); + +/** + * @name Button + * @param {string} props.text - The text to be displayed on the button. + * @param {string} props.type - The type of the button. Defaults to 'button'. + * @param {string} props.target - The target attribute for the anchor tag. Defaults to '_self'. + * @param {React.ReactNode} props.icon - The icon to be displayed on the button. + * @param {string} props.iconPosition - The position of the icon. Defaults to 'right'. + * @param {string} props.className - The class name to be applied to the button. + * @param {string} props.bgClassName - The class name to be applied to the button's background. + * @param {string} props.textClassName - The class name to be applied to the button's text. + * @param {string} props.buttonSize - The size of the button. Defaults to 'default'. + * @param {string} props.href - The href attribute for the anchor tag. + * @description The Button component is a reusable button component that can be used to render a button or an anchor tag + * @description The component accepts button or anchor tag props based on the presence of the href prop. + * @description If the href prop is present, the component will render an anchor tag, + * otherwise it will render a button tag. + */ +export default function Button({ + text, + type = 'button', + target = '_self', + icon, + iconPosition = 'right', + className, + bgClassName = twMerge('bg-primary-500 hover:bg-primary-400'), + textClassName = twMerge('text-white'), + buttonSize, + ...props +}: IButtonProps): React.ReactElement { + const smallButtonClasses = twMerge(`${bgClassName} ${textClassName} transition-all duration-500 + ease-in-out rounded-md px-3 py-2 text-sm font-medium tracking-heading ${className || ''}`); + const classNames = twMerge(`${bgClassName} ${textClassName} transition-all duration-500 ease-in-out + rounded-md px-4 py-3 text-md font-semibold tracking-heading ${className || ''}`); + + if (!props.href) { + return ( + + ); + } + + return ( + + {icon && iconPosition === 'left' && {icon}} + {text} + {icon && iconPosition === 'right' && {icon}} + + ); +} diff --git a/components/buttons/ChapterSuggestion.tsx b/components/buttons/ChapterSuggestion.tsx new file mode 100644 index 00000000000..1addc113fe5 --- /dev/null +++ b/components/buttons/ChapterSuggestion.tsx @@ -0,0 +1,52 @@ +import Link from 'next/link'; +import type { HTMLAttributeAnchorTarget } from 'react'; +import type { Url } from 'url'; + +import IconArrowRight from '../icons/ArrowRight'; + +export interface IChapterSuggestionProps { + href: string | Url; + target?: HTMLAttributeAnchorTarget; + title: string; + description: string; + linkText: string; + className?: string; +} + +/** + * + * @param {Object} props - The props of the component + * @param {string} props.href - The URL of the chapter + * @param {string} props.target - The target of the link + * @param {string} props.title - The title of the chapter + * @param {string} props.description - The description of the chapter + * @param {string} props.linkText - The text of the link + * @param {string} props.className - The class name of the component + */ +export default function ChapterSuggestion({ + href = '/', + target = '_self', + title, + description, + linkText, + className +}: IChapterSuggestionProps) { + return ( + +
{title}
+

{description}

+

+ {linkText} + +

+ + ); +} diff --git a/components/buttons/ChapterSuggestions.tsx b/components/buttons/ChapterSuggestions.tsx new file mode 100644 index 00000000000..2986418271a --- /dev/null +++ b/components/buttons/ChapterSuggestions.tsx @@ -0,0 +1,30 @@ +import type { IChapterSuggestionProps } from './ChapterSuggestion'; +import ChapterSuggestion from './ChapterSuggestion'; + +interface IChapterSuggestionsProps { + suggestions: IChapterSuggestionProps[]; + className?: string; +} + +/** + * + * @param {Object} props - The props of the component + * @param {Array} props.suggestions - The suggestions of the chapter + * @param {string} props.className - The class name of the component + */ +export default function ChapterSuggestions({ suggestions = [], className = '' }: IChapterSuggestionsProps) { + return ( +
+ {suggestions.map((suggestion, index) => ( + + ))} +
+ ); +} diff --git a/components/buttons/DocsButton.tsx b/components/buttons/DocsButton.tsx new file mode 100644 index 00000000000..a2cbd32f3b4 --- /dev/null +++ b/components/buttons/DocsButton.tsx @@ -0,0 +1,80 @@ +import Link from 'next/link'; + +import type { IDocs } from '@/types/post'; + +export interface IDocsButtonProps { + post: IDocs[number]; + className?: string; +} + +/** + * @description The DocsButton component is a button that links to the previous and next pages of the documentation. + * @param {Object} props - The props of the component + * @param {IPost} props.post - The post object + * @param {string} props.className - The class name of the component + * @returns {JSX.Element} The DocsButton component + */ +export default function DocsButton({ post, className = '' }: IDocsButtonProps) { + return ( +
+
+ {post?.prevPage && ( + +
+
+ + + +
Go Back
+
+
+ {post.prevPage.title} +
+
+ + )} +
+
+ {post?.nextPage && ( + +
+
+
Up Next
+ + + +
+
+ {post.nextPage.title} +
+
+ + )} +
+
+ ); +} diff --git a/components/buttons/GitHubIssue.tsx b/components/buttons/GitHubIssue.tsx new file mode 100644 index 00000000000..e4ba39116bb --- /dev/null +++ b/components/buttons/GitHubIssue.tsx @@ -0,0 +1,21 @@ +import React from 'react'; + +/** + * @description The GitHubIssue component is a button that links to the GitHub issue creation page. + * @param {string} props.className - The class name to be applied to the button. + */ +export default function GitHubIssue({ className = '' }) { + return ( + + Github:AsyncAPI + Create Issue on GitHub + + ); +} diff --git a/components/buttons/GithubButton.tsx b/components/buttons/GithubButton.tsx new file mode 100644 index 00000000000..d60b0ce5581 --- /dev/null +++ b/components/buttons/GithubButton.tsx @@ -0,0 +1,45 @@ +import IconGithub from '../icons/Github'; +import Button from './Button'; +import type { IButtonDefaultProps } from './types'; +// TODO: add this again when we have i18n +// import { useTranslation } from '../../lib/i18n' + +interface IGithubButtonProps extends IButtonDefaultProps { + inNav?: boolean; +} + +/** + * @description The GithubButton component is a button that links to the AsyncAPI GitHub repository. + * @param {string} props.text - The text to display on the button. + * @param {string} props.href - The href attribute for the anchor tag. + * @param {string} props.target - The target attribute for the anchor tag. + * @param {string} props.iconPosition - The position of the icon in the button. + * @param {string} props.className - The class name to be applied to the button. + */ +export default function GithubButton({ + text = 'githubButton', + href = 'https://github.com/asyncapi', + target = '_blank', + iconPosition = 'left', + className, + inNav +}: IGithubButtonProps) { + // TODO: add this again when we have i18n + // const { t } = useTranslation("common"); + + return ( + + )} + + ); +} + +export default ScrollButton; diff --git a/components/buttons/SlackButton.tsx b/components/buttons/SlackButton.tsx new file mode 100644 index 00000000000..284e8a9c105 --- /dev/null +++ b/components/buttons/SlackButton.tsx @@ -0,0 +1,34 @@ +import IconSlack from '../icons/Slack'; +import Button from './Button'; +import type { IButtonDefaultProps } from './types'; + +interface ISlackButtonProps extends IButtonDefaultProps {} + +/** + * @description The SlackButton component is a button that links to the AsyncAPI Slack channel. + * @param {string} props.text - The text to display on the button. + * @param {string} props.href - The href attribute for the anchor tag. + * @param {string} props.target - The target attribute for the anchor tag. + * @param {string} props.iconPosition - The position of the icon in the button. + * @param {string} props.className - The class name to be applied to the button. + */ +export default function SlackButton({ + text = 'Join on Slack', + href = '/slack-invite', + target = '_blank', + iconPosition = 'left', + className +}: ISlackButtonProps) { + return ( +