From ec8f1bcbfc6b8eac94432983eda74deb90c90681 Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Thu, 14 Mar 2024 13:53:37 +0530 Subject: [PATCH 01/16] migrated tools/Tags.tsx to TypeScript --- components/tools/Tags.tsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 components/tools/Tags.tsx diff --git a/components/tools/Tags.tsx b/components/tools/Tags.tsx new file mode 100644 index 00000000000..b1c9e5ccda9 --- /dev/null +++ b/components/tools/Tags.tsx @@ -0,0 +1,25 @@ +interface SelectTagsProps { + name?: string; + bgColor: string; + borderColor: string; +}; + +/** + * @description This component displays tags. + * + * @param {SelectTagsProps} props - The props for the Select Tags component. + * @param {string} props.name - The content to be displayed inside the tag. + * @param {string} props.bgColor - The color of the tag. + * @param {string} props.borderColor - The border color of the tag. + */ +export default function SelectTags({ + name = '', + bgColor, + borderColor +} : SelectTagsProps) { + return ( +
+ {name} +
+ ); +}; From 8e3d9e67401e396d101f8d3d0d57276ae3ad3ad3 Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Thu, 14 Mar 2024 15:22:30 +0530 Subject: [PATCH 02/16] migrated tools/CardData to typescript --- components/tools/CardData.tsx | 110 ++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 components/tools/CardData.tsx diff --git a/components/tools/CardData.tsx b/components/tools/CardData.tsx new file mode 100644 index 00000000000..837d0bbc7ec --- /dev/null +++ b/components/tools/CardData.tsx @@ -0,0 +1,110 @@ +import React, { useEffect, useRef, useState } from 'react'; +import TextTruncate from 'react-text-truncate'; + +import InfoIcon from '../icons/InfoIcon'; + +type VisibleType = Record; + +interface CardDataProps { + className: string; + visible: VisibleType; + heading: string; + data: string; + read: boolean; + setRead: React.Dispatch>; + setVisible: React.Dispatch>; + type: string; +}; + +export const CardData = ({ + className, + visible, + heading, + data, + read, + setRead, + setVisible, + type +}: CardDataProps) => { + const [outsideClick, setOutsideClick] = useState(true); + const [description, setShowDescription] = useState(false); + const initial = { + lang: false, + tech: false, + category: false, + pricing: false, + ownership: false + }; + const domNode = useRef(null); + + useEffect(() => { + const divHeight = domNode.current?.offsetHeight || 0; + const numberOfLines = divHeight / 20; + + if (numberOfLines > 3) { + setShowDescription(true); + } else { + setShowDescription(false); + } + }, [visible]); + + useEffect(() => { + const maybeHandler = (event: MouseEvent) => { + setOutsideClick(true); + if (domNode.current && !domNode.current.contains(event.target as Node)) { + setOutsideClick(false); + } + }; + + document.addEventListener('mousedown', maybeHandler); + + return () => { + document.removeEventListener('mousedown', maybeHandler); + }; + }, []); + + return ( +
+ {heading} + + {outsideClick && visible[type] && ( + + {read ? ( + data + ) : ( +
+ +
+ )} + {description && ( + + )} +
+ )} + +
+
+ ); +}; From 6e066b363b25bc923fdd700023640a3ff9634edf Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Fri, 15 Mar 2024 10:07:39 +0530 Subject: [PATCH 03/16] migrated ToolsCard component --- components/tools/CardData.tsx | 12 ++ components/tools/ToolsCard.tsx | 218 +++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 components/tools/ToolsCard.tsx diff --git a/components/tools/CardData.tsx b/components/tools/CardData.tsx index 837d0bbc7ec..ec26b6fd83e 100644 --- a/components/tools/CardData.tsx +++ b/components/tools/CardData.tsx @@ -16,6 +16,18 @@ interface CardDataProps { type: string; }; +/** + * @description This component displays Card. + * + * @param {SelectTagsProps} props - The props for the Cards Data component. + * @param {string} props.className - Additional CSS classes for the component. + * @param {VisibleType} props.visible - Visibility status for different types. + * @param {string} props.heading - The heading text. + * @param {string} props.data - The data to be displayed. + * @param {boolean} props.read - Read status. + * @param {React.Dispatch>} props.setRead - Function to set read status. + * @param {React.Dispatch>} props.type - Function to set visibility status. + */ export const CardData = ({ className, visible, diff --git a/components/tools/ToolsCard.tsx b/components/tools/ToolsCard.tsx new file mode 100644 index 00000000000..d5ca3026e3c --- /dev/null +++ b/components/tools/ToolsCard.tsx @@ -0,0 +1,218 @@ +import { useEffect, useRef, useState } from 'react'; +import TextTruncate from 'react-text-truncate'; + +import { HeadingTypeStyle } from '@/types/typography/Heading'; +import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; + +import Data from '../../scripts/tools/tools-schema.json'; +import Heading from '../typography/Heading'; +import Paragraph from '../typography/Paragraph'; +import { CardData } from './CardData'; +import Tag from './Tags'; + +type VisibleType = Record; + +interface Link { + repoUrl?: string; + websiteUrl?: string; + docsUrl?: string; +}; + +interface Filter { + language: { name: string; color: string; borderColor: string }[]; + technology: { name: string; color: string; borderColor: string }[]; + hasCommercial: boolean; +}; + +interface ToolData { + title: string; + description: string; + links: Link; + filters: Filter; +}; + +interface ToolsCardProp { + toolData: ToolData; +} + +/** + * @description This component displays a card for a tool. + * + * @param {ToolsCardProp} props - Props for the ToolsCard component. + * @param {ToolData} props.toolData - Data of the tool. + */ +export default function ToolsCard({ toolData }: ToolsCardProp) { + const [showDescription, setShowDescription] = useState(false); + const [showMoreDescription, setShowMoreDescription] = useState(false); + const [readMore, setReadMore] = useState(false); + const descriptionRef = useRef(null); + + useEffect(() => { + const divHeight = descriptionRef.current?.offsetHeight || 0; + const numberOfLines = divHeight / 20; + + if (numberOfLines > 3) { + setShowMoreDescription(true); + } else { + setShowMoreDescription(false); + }; + }, []); + + let onGit = false; + + if (toolData.links.repoUrl) { + const url = new URL(toolData.links.repoUrl); + + if (url.host === 'github.com') { + onGit = true; + } else { + onGit = false; + } + } + + const [visible, setVisible] = useState({ + lang: false, + tech: false, + desc: false + }); + + return ( +
+
+
+
+ {toolData.title} +
(setTimeout(() => { if (!visible.desc) setVisible({ ...visible, desc: true }); }, 400))} + > + (setTimeout(() => { if (visible.desc) setVisible({ ...visible, desc: false }); }, 300))} + > + {toolData.filters.hasCommercial === false ? 'Open Source' : 'Commercial'} + {visible.desc && + {Data.properties.filters.properties.hasCommercial.description} + } + +
+
+
+ +
(setTimeout(() => { if (showMoreDescription) setShowDescription(true); }, 500))}> +
+
+ {showDescription &&
(setShowDescription(false))}> + + {toolData.description} + +
} +
+
+
+
+
+ {(toolData?.filters?.language || toolData?.filters?.technology?.length > 0) ?
+ {toolData.filters.language &&
+ +
+ {toolData.filters.language.map((item, index) => ( + + ))} +
+
} + {toolData.filters.technology.length > 0 &&
+ +
+ {toolData.filters.technology.map((item, index) => ( + + ))} +
+
} +
: +
+
No further details provided
+
} +
+ {(toolData.links.repoUrl || toolData.links.websiteUrl || toolData.links.docsUrl) && <> +
+
+ {toolData.links.repoUrl && <> + {onGit ? + +
+ GitHub +
View Github
+
+
: + +
+
View Source Code
+
+
+ } + } + {toolData.links.websiteUrl && ( + +
+ Share +
Visit Website
+
+
+ )} + {toolData.links.docsUrl && ( + +
+ Docs +
Visit Docs
+
+
+ )} +
+ } +
+ ); +}; From 01f8f95168572d741e1747201e25b0b160e587a0 Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Fri, 15 Mar 2024 11:21:20 +0530 Subject: [PATCH 04/16] migrated tools list to typescript --- components/tools/ToolsCard.tsx | 24 ++---------- components/tools/ToolsList.tsx | 51 ++++++++++++++++++++++++++ types/components/tools/ToolDataType.ts | 20 ++++++++++ 3 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 components/tools/ToolsList.tsx create mode 100644 types/components/tools/ToolDataType.ts diff --git a/components/tools/ToolsCard.tsx b/components/tools/ToolsCard.tsx index d5ca3026e3c..d1f8c9ef0c4 100644 --- a/components/tools/ToolsCard.tsx +++ b/components/tools/ToolsCard.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import TextTruncate from 'react-text-truncate'; +import type { ToolData } from '@/types/components/tools/ToolDataType'; import { HeadingTypeStyle } from '@/types/typography/Heading'; import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; @@ -12,25 +13,6 @@ import Tag from './Tags'; type VisibleType = Record; -interface Link { - repoUrl?: string; - websiteUrl?: string; - docsUrl?: string; -}; - -interface Filter { - language: { name: string; color: string; borderColor: string }[]; - technology: { name: string; color: string; borderColor: string }[]; - hasCommercial: boolean; -}; - -interface ToolData { - title: string; - description: string; - links: Link; - filters: Filter; -}; - interface ToolsCardProp { toolData: ToolData; } @@ -139,7 +121,7 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { ))} } - {toolData.filters.technology.length > 0 &&
+ {toolData?.filters?.technology?.length > 0 &&
- {toolData.filters.technology.map((item, index) => ( + {toolData?.filters?.technology.map((item, index) => ( + {Object.keys(toolsListData).map((categoryName, index) => { + if (toolsListData[categoryName].toolsList.length > 0) return ( +
+ + {categoryName} + + + {toolsListData[categoryName].description} + +
+
+ {toolsListData[categoryName].toolsList.map((tool, toolIndex) => ( + + ))} +
+
+ ); + + return null; + })} +
+ ); +}; diff --git a/types/components/tools/ToolDataType.ts b/types/components/tools/ToolDataType.ts new file mode 100644 index 00000000000..be262426ecd --- /dev/null +++ b/types/components/tools/ToolDataType.ts @@ -0,0 +1,20 @@ +export interface Link { + repoUrl?: string; + websiteUrl?: string; + docsUrl?: string; +}; + +export interface Filter { + categories: string[]; + hasCommercial: boolean; + isAsyncAPIOwner: boolean; + language: { name: string; color: string; borderColor: string }[]; + technology: { name: string; color: string; borderColor: string }[]; +}; + +export interface ToolData { + title: string; + description: string; + links: Link; + filters: Filter; +}; From 5b859d14eaec8f22d68e59c0ed311a8da331918d Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Mon, 18 Mar 2024 08:17:25 +0530 Subject: [PATCH 05/16] migrated CategoryDropdown to TypeScript --- components/tools/CategoryDropdown.tsx | 26 ++++++++++++++++++++++++++ components/tools/ToolsList.tsx | 9 +-------- types/components/tools/ToolDataType.ts | 9 ++++++++- 3 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 components/tools/CategoryDropdown.tsx diff --git a/components/tools/CategoryDropdown.tsx b/components/tools/CategoryDropdown.tsx new file mode 100644 index 00000000000..53c42d010e7 --- /dev/null +++ b/components/tools/CategoryDropdown.tsx @@ -0,0 +1,26 @@ +import ToolsDataList from '../../config/tools.json'; +import type { ToolsListType } from '@/types/components/tools/ToolDataType'; + +interface CategoryDropdownProps { + setopenCategory:React.Dispatch>; +}; + +const ToolsData = ToolsDataList as ToolsListType; + +export default function CategoryDropdown({ setopenCategory } : CategoryDropdownProps) { + + return ( +
+
+ { Object.keys(ToolsData).map((categoryName, index) => { + // displaying tools category having atleast one tool + if (ToolsData[categoryName].toolsList.length > 0) return ( +
setopenCategory(false) }> + { categoryName } +
) + }) } +
+
+ ) +}; diff --git a/components/tools/ToolsList.tsx b/components/tools/ToolsList.tsx index e7e5d991576..ec94a178c55 100644 --- a/components/tools/ToolsList.tsx +++ b/components/tools/ToolsList.tsx @@ -1,4 +1,4 @@ -import type { ToolData } from '@/types/components/tools/ToolDataType'; +import type { ToolsListType } from '@/types/components/tools/ToolDataType'; import { HeadingTypeStyle } from '@/types/typography/Heading'; import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; @@ -6,13 +6,6 @@ import Heading from '../typography/Heading'; import Paragraph from '../typography/Paragraph'; import ToolsCard from './ToolsCard'; -interface ToolsListType { - [category: string]: { - description: string; - toolsList: ToolData[]; - } -} - interface ToolsListProp { toolsListData: ToolsListType; } diff --git a/types/components/tools/ToolDataType.ts b/types/components/tools/ToolDataType.ts index be262426ecd..fd11ae40f0e 100644 --- a/types/components/tools/ToolDataType.ts +++ b/types/components/tools/ToolDataType.ts @@ -8,7 +8,7 @@ export interface Filter { categories: string[]; hasCommercial: boolean; isAsyncAPIOwner: boolean; - language: { name: string; color: string; borderColor: string }[]; + language?: { name: string; color: string; borderColor: string }[]; technology: { name: string; color: string; borderColor: string }[]; }; @@ -18,3 +18,10 @@ export interface ToolData { links: Link; filters: Filter; }; + +export interface ToolsListType { + [category: string]: { + description: string; + toolsList: ToolData[]; + } +} From 9946faa9931a9f046fe445098d10b9e87374233b Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Mon, 18 Mar 2024 08:38:48 +0530 Subject: [PATCH 06/16] fixed lint issues --- components/tools/CategoryDropdown.tsx | 37 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/components/tools/CategoryDropdown.tsx b/components/tools/CategoryDropdown.tsx index 53c42d010e7..7ec64528a8f 100644 --- a/components/tools/CategoryDropdown.tsx +++ b/components/tools/CategoryDropdown.tsx @@ -1,26 +1,35 @@ -import ToolsDataList from '../../config/tools.json'; import type { ToolsListType } from '@/types/components/tools/ToolDataType'; +import ToolsDataList from '../../config/tools.json'; + interface CategoryDropdownProps { - setopenCategory:React.Dispatch>; + setopenCategory: React.Dispatch>; }; const ToolsData = ToolsDataList as ToolsListType; -export default function CategoryDropdown({ setopenCategory } : CategoryDropdownProps) { - +/** + * @description This component displays Category Dropdown. + * + * @param {React.Dispatch>} props.setopenCategory - Function to set dropdown status. + */ +export default function CategoryDropdown({ setopenCategory }: CategoryDropdownProps) { return ( -
-
- { Object.keys(ToolsData).map((categoryName, index) => { +
+
+ {Object.keys(ToolsData).map((categoryName, index) => { // displaying tools category having atleast one tool - if (ToolsData[categoryName].toolsList.length > 0) return ( -
setopenCategory(false) }> - { categoryName } -
) - }) } + if (ToolsData[categoryName].toolsList.length > 0) { + return ( +
setopenCategory(false)}> + {categoryName} +
); + } + + return null; + })}
- ) + ); }; From f252944287e4bdd34c04266a6aeac5afd8fff87a Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Mon, 18 Mar 2024 10:04:20 +0530 Subject: [PATCH 07/16] migrated filter dropdown --- components/tools/FiltersDropdown.tsx | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 components/tools/FiltersDropdown.tsx diff --git a/components/tools/FiltersDropdown.tsx b/components/tools/FiltersDropdown.tsx new file mode 100644 index 00000000000..c43ab21121f --- /dev/null +++ b/components/tools/FiltersDropdown.tsx @@ -0,0 +1,57 @@ +import { twMerge } from 'tailwind-merge'; + +interface DataListType { + name: string; + color: string; + borderColor: string; +}; + +interface FiltersDropdownProps { + dataList: DataListType[]; + checkedOptions: string[]; + setStateFunction: React.Dispatch>; + className?: string; +}; + +/** + * @description This component displays Filter Dropdown Component. + * + * @param {DataListType[]} props.dataList - List of filter options. + * @param {string[]} props.checkedOptions - List of options that are currently checked. + * @param {React.Dispatch>} props.setStateFunction - Function to set check state of options. + * @param {string} props.className - Additional CSS classes for the component. + */ +export default function FiltersDropdown({ + dataList = [], + checkedOptions = [], + setStateFunction, + className = '' +}: FiltersDropdownProps) { + const handleClickOption = (event: React.MouseEvent, option: string) => { + const isChecked = checkedOptions.includes(option); + const updatedOptions = isChecked + ? checkedOptions.filter(item => item !== option) + : [...checkedOptions, option]; + + setStateFunction(updatedOptions); + }; + + return ( +
+ {dataList.map((data, index) => { + const checked = checkedOptions.includes(data.name); + + return ( +
handleClickOption(event, data.name)} + > + {checked ? checked : unchecked} +
{data.name}
+
+ ); + })} +
+ ); +}; From 190353920ee6bf00b2b6696b13f2d3a105c19bd9 Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Mon, 18 Mar 2024 10:18:46 +0530 Subject: [PATCH 08/16] migrated filter display --- components/tools/FilterDisplay.tsx | 48 ++++++++++++++++++++++++++++ components/tools/FiltersDropdown.tsx | 12 +++---- 2 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 components/tools/FilterDisplay.tsx diff --git a/components/tools/FilterDisplay.tsx b/components/tools/FilterDisplay.tsx new file mode 100644 index 00000000000..e79ff3c5e7c --- /dev/null +++ b/components/tools/FilterDisplay.tsx @@ -0,0 +1,48 @@ +import { twMerge } from 'tailwind-merge'; + +interface FiltersDisplayProps { + checkedOptions?: string[]; + setCheckedOptions: React.Dispatch>; +}; + +/** + * @description This component displays Filters. + * + * @param {string[]} props.checkedOptions - List of options that are currently checked. + * @param {React.Dispatch>} props.setCheckedOptions - Function to set check state of options. + */ +export default function FiltersDisplay({ + checkedOptions = [], + setCheckedOptions +}: FiltersDisplayProps) { + // function to clear selected filters + const handleClickOption = (event: React.MouseEvent, option: string, checkedOptionsList: typeof checkedOptions, setCheckedOptionsList: typeof setCheckedOptions) => { + const tempValueArray = [...checkedOptionsList]; + const index = checkedOptionsList.indexOf(option); + + if (index > -1) { + tempValueArray.splice(index, 1); + } + setCheckedOptionsList(tempValueArray); + }; + + return ( + <> + {checkedOptions.length > 0 && +
+ {checkedOptions.map((items, index) => { + return ( +
+
{items}
+ +
+ ); + })} +
} + + ); +}; diff --git a/components/tools/FiltersDropdown.tsx b/components/tools/FiltersDropdown.tsx index c43ab21121f..efb35cd611e 100644 --- a/components/tools/FiltersDropdown.tsx +++ b/components/tools/FiltersDropdown.tsx @@ -7,9 +7,9 @@ interface DataListType { }; interface FiltersDropdownProps { - dataList: DataListType[]; - checkedOptions: string[]; - setStateFunction: React.Dispatch>; + dataList?: DataListType[]; + checkedOptions?: string[]; + setCheckedOptions: React.Dispatch>; className?: string; }; @@ -18,13 +18,13 @@ interface FiltersDropdownProps { * * @param {DataListType[]} props.dataList - List of filter options. * @param {string[]} props.checkedOptions - List of options that are currently checked. - * @param {React.Dispatch>} props.setStateFunction - Function to set check state of options. + * @param {React.Dispatch>} props.setCheckedOptions - Function to set check state of options. * @param {string} props.className - Additional CSS classes for the component. */ export default function FiltersDropdown({ dataList = [], checkedOptions = [], - setStateFunction, + setCheckedOptions, className = '' }: FiltersDropdownProps) { const handleClickOption = (event: React.MouseEvent, option: string) => { @@ -33,7 +33,7 @@ export default function FiltersDropdown({ ? checkedOptions.filter(item => item !== option) : [...checkedOptions, option]; - setStateFunction(updatedOptions); + setCheckedOptions(updatedOptions); }; return ( From 07f2f0865fd40d59e331767cdcb8bf3645cd3941 Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Tue, 19 Mar 2024 12:38:52 +0530 Subject: [PATCH 09/16] migrated filter component --- components/tools/CardData.tsx | 21 +- components/tools/Filters.tsx | 203 ++++++++++++++++++ .../{FilterDisplay.tsx => FiltersDisplay.tsx} | 0 components/tools/FiltersDropdown.tsx | 12 +- components/tools/ToolsCard.tsx | 20 +- scripts/tools/categorylist.js | 100 --------- scripts/tools/categorylist.ts | 102 +++++++++ types/components/tools/ToolDataType.ts | 39 +++- 8 files changed, 363 insertions(+), 134 deletions(-) create mode 100644 components/tools/Filters.tsx rename components/tools/{FilterDisplay.tsx => FiltersDisplay.tsx} (100%) delete mode 100644 scripts/tools/categorylist.js create mode 100644 scripts/tools/categorylist.ts diff --git a/components/tools/CardData.tsx b/components/tools/CardData.tsx index ec26b6fd83e..96bdbe3d910 100644 --- a/components/tools/CardData.tsx +++ b/components/tools/CardData.tsx @@ -1,19 +1,19 @@ import React, { useEffect, useRef, useState } from 'react'; import TextTruncate from 'react-text-truncate'; -import InfoIcon from '../icons/InfoIcon'; +import type { VisibleDataListType } from '@/types/components/tools/ToolDataType'; -type VisibleType = Record; +import InfoIcon from '../icons/InfoIcon'; interface CardDataProps { - className: string; - visible: VisibleType; + visible: VisibleDataListType; heading: string; data: string; read: boolean; setRead: React.Dispatch>; - setVisible: React.Dispatch>; - type: string; + setVisible: React.Dispatch>; + type: keyof VisibleDataListType; + className?: string; }; /** @@ -21,22 +21,23 @@ interface CardDataProps { * * @param {SelectTagsProps} props - The props for the Cards Data component. * @param {string} props.className - Additional CSS classes for the component. - * @param {VisibleType} props.visible - Visibility status for different types. + * @param {VisibleDataListType} props.visible - Visibility status for different types. * @param {string} props.heading - The heading text. * @param {string} props.data - The data to be displayed. * @param {boolean} props.read - Read status. * @param {React.Dispatch>} props.setRead - Function to set read status. - * @param {React.Dispatch>} props.type - Function to set visibility status. + * @param {React.Dispatch>} props.setVisible - Function to set visibility status. + * @param {string} props.type - Type of the card data. */ export const CardData = ({ - className, visible, heading, data, read, setRead, setVisible, - type + type, + className = '' }: CardDataProps) => { const [outsideClick, setOutsideClick] = useState(true); const [description, setShowDescription] = useState(false); diff --git a/components/tools/Filters.tsx b/components/tools/Filters.tsx new file mode 100644 index 00000000000..36566d1f9e6 --- /dev/null +++ b/components/tools/Filters.tsx @@ -0,0 +1,203 @@ +import { useRouter } from 'next/router'; +import { useContext, useEffect, useState } from 'react'; +import { twMerge } from 'tailwind-merge'; + +import type { Language, Technology, VisibleDataListType } from '@/types/components/tools/ToolDataType'; + +import tags from '../../config/all-tags.json'; +import ToolFilter, { ToolFilterContext } from '../../context/ToolFilterContext'; +import categoryList from '../../scripts/tools/categorylist'; +import Data from '../../scripts/tools/tools-schema.json'; +import Button from '../buttons/Button'; +import ArrowDown from '../icons/ArrowDown'; +import { CardData } from './CardData'; +import FiltersDisplay from './FiltersDisplay'; +import FiltersDropdown from './FiltersDropdown'; + +interface FiltersProps { + setOpenFilter: React.Dispatch>; +} + +/** + * @description This component displays Filters. + * @param {FiltersProps} props - Props for Filters component. + * @param {React.Dispatch>} props.setOpenFilter - Function to set the state of filter. + */ +export default function Filters({ setOpenFilter }: FiltersProps) { + const router = useRouter(); + // all the filter state variables and functions are extracted from the Context to set filters according to the UI. + const { isPaid, isAsyncAPIOwner, languages, technologies, categories } = useContext(ToolFilterContext); + + // State variables to operate dropdowns of respective filters + const [openLanguage, setopenLanguage] = useState(false); + const [openTechnology, setopenTechnology] = useState(false); + const [openCategory, setopenCategory] = useState(false); + + // Filter state variables for user checked values are created, initialising it with the values already set by user. + const [checkPaid, setCheckPaid] = useState(isPaid); + const [checkedLanguage, setCheckedLanguage] = useState(languages); + const [checkedTechnology, setCheckedTechnology] = useState(technologies); + const [checkedCategory, setCheckedCategory] = useState(categories); + const [checkOwner, setCheckOwner] = useState(isAsyncAPIOwner); + + // useEffect hook used to update the UI elements + useEffect(() => { + setCheckedLanguage(languages); + setCheckedTechnology(technologies); + setCheckedCategory(categories); + setCheckPaid(isPaid); + setCheckOwner(isAsyncAPIOwner); + }, [languages, technologies, categories, isPaid, isAsyncAPIOwner]); + + // contains the list of languages and technologies + const languageList = tags.languages as Language[]; + const technologyList = tags.technologies as Technology[]; + + // For Showing language, technology and category information + const [visible, setVisible] = useState({ + lang: false, + tech: false, + category: false, + pricing: false, + ownership: false + }); + + // For showing the read more content of Language and Category information + const [readMore, setReadMore] = useState(false); + + // function to apply all the filters, which are selected, when `Apply Filters` is clicked. + const handleApplyFilters = () => { + setOpenFilter(false); + + const searchParams = new URLSearchParams(); + + // Set the params key only when the default value of the key changes. This is to know when the user actually applies filter(s). + + if (checkOwner) { + searchParams.set('owned', checkOwner.toString()); + } + if (checkedTechnology.length > 0) { + searchParams.set('techs', checkedTechnology.join(',')); + } + if (checkedLanguage.length > 0) { + searchParams.set('langs', checkedLanguage.join(',')); + } + if (checkedTechnology.length > 0) { + searchParams.set('techs', checkedTechnology.join(',')); + } + if (checkedCategory.length > 0) { + searchParams.set('categories', checkedCategory.join(',')); + } + + router.push({ + pathname: '/tools', + query: searchParams.toString() + }, undefined, { shallow: true }); + }; + + // function to undo all the filters when `Undo Changes` is clicked. + const undoChanges = () => { + setCheckedLanguage(languages); + setCheckedTechnology(technologies); + setCheckedCategory(categories); + setCheckPaid(isPaid); + setCheckOwner(isAsyncAPIOwner); + }; + + return ( + +
+
+
+
+ +
+
+ Undo Changes +
+
+
+
(checkPaid === 'free' ? setCheckPaid('all') : setCheckPaid('free'))}> +
Open Source
+ Free +
+
(checkPaid === 'paid' ? setCheckPaid('all') : setCheckPaid('paid'))}> +
Commercial
+ Paid +
+
+
+
+
+
+ +
+
+ +
+ Show only AsyncAPI-owned tools +
+
+
+
+
+ +
+
setopenLanguage(!openLanguage)}> +
+ {/* eslint-disable-next-line no-nested-ternary */} + {checkedLanguage.length > 0 ? (checkedLanguage.length === 1 ? '1 option selected' : `${checkedLanguage.length} options selected`) : 'Select Languages...'} +
+ +
+ {openLanguage &&
+ +
} + +
+
+
+
+ +
+
setopenTechnology(!openTechnology)}> +
+ {/* eslint-disable-next-line no-nested-ternary */} + {checkedTechnology.length > 0 ? (checkedTechnology.length === 1 ? '1 option selected' : `${checkedTechnology.length} options selected`) : 'Select Technologies...'} +
+ +
+ {openTechnology &&
+ +
} + +
+
+
+
+ +
+
setopenCategory(!openCategory)}> +
+ {/* eslint-disable-next-line no-nested-ternary */} + {checkedCategory.length > 0 ? (checkedCategory.length === 1 ? '1 option selected' : `${checkedCategory.length} options selected`) : 'Select Categories...'} +
+ +
+ {openCategory &&
+ +
} + +
+
+
+
+
+
+
+ ); +}; diff --git a/components/tools/FilterDisplay.tsx b/components/tools/FiltersDisplay.tsx similarity index 100% rename from components/tools/FilterDisplay.tsx rename to components/tools/FiltersDisplay.tsx diff --git a/components/tools/FiltersDropdown.tsx b/components/tools/FiltersDropdown.tsx index efb35cd611e..561e90d2c38 100644 --- a/components/tools/FiltersDropdown.tsx +++ b/components/tools/FiltersDropdown.tsx @@ -1,13 +1,11 @@ import { twMerge } from 'tailwind-merge'; -interface DataListType { - name: string; - color: string; - borderColor: string; -}; +import type { Category, Language, Technology } from '@/types/components/tools/ToolDataType'; + +type DataList = Language[] | Technology[] | Category[]; interface FiltersDropdownProps { - dataList?: DataListType[]; + dataList?: DataList; checkedOptions?: string[]; setCheckedOptions: React.Dispatch>; className?: string; @@ -16,7 +14,7 @@ interface FiltersDropdownProps { /** * @description This component displays Filter Dropdown Component. * - * @param {DataListType[]} props.dataList - List of filter options. + * @param {DataList} props.dataList - List of filter options. * @param {string[]} props.checkedOptions - List of options that are currently checked. * @param {React.Dispatch>} props.setCheckedOptions - Function to set check state of options. * @param {string} props.className - Additional CSS classes for the component. diff --git a/components/tools/ToolsCard.tsx b/components/tools/ToolsCard.tsx index d1f8c9ef0c4..333f33830a6 100644 --- a/components/tools/ToolsCard.tsx +++ b/components/tools/ToolsCard.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import TextTruncate from 'react-text-truncate'; -import type { ToolData } from '@/types/components/tools/ToolDataType'; +import type { ToolData, VisibleDataListType } from '@/types/components/tools/ToolDataType'; import { HeadingTypeStyle } from '@/types/typography/Heading'; import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; @@ -11,8 +11,6 @@ import Paragraph from '../typography/Paragraph'; import { CardData } from './CardData'; import Tag from './Tags'; -type VisibleType = Record; - interface ToolsCardProp { toolData: ToolData; } @@ -42,7 +40,7 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { let onGit = false; - if (toolData.links.repoUrl) { + if (toolData?.links?.repoUrl) { const url = new URL(toolData.links.repoUrl); if (url.host === 'github.com') { @@ -52,7 +50,7 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { } } - const [visible, setVisible] = useState({ + const [visible, setVisible] = useState({ lang: false, tech: false, desc: false @@ -72,7 +70,7 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { className='group relative' onMouseLeave={() => (setTimeout(() => { if (visible.desc) setVisible({ ...visible, desc: false }); }, 300))} > - {toolData.filters.hasCommercial === false ? 'Open Source' : 'Commercial'} + {toolData.filters?.hasCommercial === false ? 'Open Source' : 'Commercial'} {visible.desc && {Data.properties.filters.properties.hasCommercial.description} } @@ -98,7 +96,7 @@ export default function ToolsCard({ toolData }: ToolsCardProp) {

- {(toolData?.filters?.language || toolData?.filters?.technology?.length > 0) ?
+ {(toolData.filters?.language || toolData?.filters?.technology?.length) ?
{toolData.filters.language &&
- {toolData.filters.language.map((item, index) => ( + {toolData.filters?.language && toolData.filters?.language.map((item, index) => (
} - {toolData?.filters?.technology?.length > 0 &&
+ {toolData.filters?.technology?.length &&
- {toolData?.filters?.technology.map((item, index) => ( + {toolData.filters?.technology && toolData.filters.technology.map((item, index) => ( No further details provided
}
- {(toolData.links.repoUrl || toolData.links.websiteUrl || toolData.links.docsUrl) && <> + {(toolData?.links?.repoUrl || toolData?.links?.websiteUrl || toolData?.links?.docsUrl) && <>
{toolData.links.repoUrl && <> diff --git a/scripts/tools/categorylist.js b/scripts/tools/categorylist.js deleted file mode 100644 index 28ef9414586..00000000000 --- a/scripts/tools/categorylist.js +++ /dev/null @@ -1,100 +0,0 @@ -// Various categories to define the category in which a tool has to be listed -const categoryList = [ - { - name: "APIs", - tag: "api", - description: "The following is a list of APIs that expose functionality related to AsyncAPI." - }, - { - name: "Code-first tools", - tag: "code-first", - description: "The following is a list of tools that generate AsyncAPI documents from your code." - }, - { - name: "Code Generators", - tag: "code-generator", - description: "The following is a list of tools that generate code from an AsyncAPI document; not the other way around." - }, - { - name: "Converters", - tag: "converter", - description: "The following is a list of tools that do not yet belong to any specific category but are also useful for the community." - }, - { - name: "Directories", - tag: "directory", - description: "The following is a list of directories that index public AsyncAPI documents." - }, - { - name: "Documentation Generators", - tag: "documentation-generator", - description: "The following is a list of tools that generate human-readable documentation from an AsyncAPI document." - }, - { - name: "Editors", - tag: "editor", - description: "The following is a list of editors or related tools that allow editing of AsyncAPI document." - }, - { - name: "UI components", - tag: "ui-component", - description: "The following is a list of UI components to view AsyncAPI documents." - }, - { - name: "DSL", - tag: "dsl", - description: "Writing YAML by hand is no fun, and maybe you don't want a GUI, so use a Domain Specific Language to write AsyncAPI in your language of choice." - }, - { - name: "Frameworks", - tag: "framework", - description: "The following is a list of API/application frameworks that make use of AsyncAPI." - }, - { - name: "GitHub Actions", - tag: "github-action", - description: "The following is a list of GitHub Actions that you can use in your workflows" - }, - { - name: "Mocking and Testing", - tag: "mocking-and-testing", - description: "The tools below take specification documents as input, then publish fake messages to broker destinations for simulation purposes. They may also check that publisher messages are compliant with schemas." - }, - { - name: "Validators", - tag: "validator", - description: "The following is a list of tools that validate AsyncAPI documents." - }, - { - name: "Compare tools", - tag: "compare-tool", - description: "The following is a list of tools that compare AsyncAPI documents." - }, - { - name: "CLIs", - tag: "cli", - description: "The following is a list of tools that you can work with in terminal or do some CI/CD automation." - }, - { - name: "Bundlers", - tag: "bundler", - description: "The following is a list of tools that you can work with to bundle AsyncAPI documents." - }, - { - name: "IDE Extensions", - tag: "ide-extension", - description: "The following is a list of extensions for different IDEs like VSCode, IntelliJ IDEA and others" - }, - { - name: "AsyncAPI Generator Templates", - tag: "generator-template", - description: "The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents." - }, - { - name: "Others", - tag: "other", - description: "The following is a list of tools that comes under Other category." - } -] - -module.exports = {categoryList} \ No newline at end of file diff --git a/scripts/tools/categorylist.ts b/scripts/tools/categorylist.ts new file mode 100644 index 00000000000..0f8d029658f --- /dev/null +++ b/scripts/tools/categorylist.ts @@ -0,0 +1,102 @@ +import { Category } from "@/types/components/tools/ToolDataType"; + +// Various categories to define the category in which a tool has to be listed +const categoryList: Category[] = [ + { + name: "APIs", + tag: "api", + description: "The following is a list of APIs that expose functionality related to AsyncAPI." + }, + { + name: "Code-first tools", + tag: "code-first", + description: "The following is a list of tools that generate AsyncAPI documents from your code." + }, + { + name: "Code Generators", + tag: "code-generator", + description: "The following is a list of tools that generate code from an AsyncAPI document; not the other way around." + }, + { + name: "Converters", + tag: "converter", + description: "The following is a list of tools that do not yet belong to any specific category but are also useful for the community." + }, + { + name: "Directories", + tag: "directory", + description: "The following is a list of directories that index public AsyncAPI documents." + }, + { + name: "Documentation Generators", + tag: "documentation-generator", + description: "The following is a list of tools that generate human-readable documentation from an AsyncAPI document." + }, + { + name: "Editors", + tag: "editor", + description: "The following is a list of editors or related tools that allow editing of AsyncAPI document." + }, + { + name: "UI components", + tag: "ui-component", + description: "The following is a list of UI components to view AsyncAPI documents." + }, + { + name: "DSL", + tag: "dsl", + description: "Writing YAML by hand is no fun, and maybe you don't want a GUI, so use a Domain Specific Language to write AsyncAPI in your language of choice." + }, + { + name: "Frameworks", + tag: "framework", + description: "The following is a list of API/application frameworks that make use of AsyncAPI." + }, + { + name: "GitHub Actions", + tag: "github-action", + description: "The following is a list of GitHub Actions that you can use in your workflows" + }, + { + name: "Mocking and Testing", + tag: "mocking-and-testing", + description: "The tools below take specification documents as input, then publish fake messages to broker destinations for simulation purposes. They may also check that publisher messages are compliant with schemas." + }, + { + name: "Validators", + tag: "validator", + description: "The following is a list of tools that validate AsyncAPI documents." + }, + { + name: "Compare tools", + tag: "compare-tool", + description: "The following is a list of tools that compare AsyncAPI documents." + }, + { + name: "CLIs", + tag: "cli", + description: "The following is a list of tools that you can work with in terminal or do some CI/CD automation." + }, + { + name: "Bundlers", + tag: "bundler", + description: "The following is a list of tools that you can work with to bundle AsyncAPI documents." + }, + { + name: "IDE Extensions", + tag: "ide-extension", + description: "The following is a list of extensions for different IDEs like VSCode, IntelliJ IDEA and others" + }, + { + name: "AsyncAPI Generator Templates", + tag: "generator-template", + description: "The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents." + }, + { + name: "Others", + tag: "other", + description: "The following is a list of tools that comes under Other category." + } +] + +export default categoryList; diff --git a/types/components/tools/ToolDataType.ts b/types/components/tools/ToolDataType.ts index fd11ae40f0e..68995f61a8e 100644 --- a/types/components/tools/ToolDataType.ts +++ b/types/components/tools/ToolDataType.ts @@ -4,18 +4,36 @@ export interface Link { docsUrl?: string; }; +export interface Language { + name: string; + color: string; + borderColor: string; +} + +export interface Technology { + name: string; + color: string; + borderColor: string; +} + +export interface Category { + name: string; + tag: string; + description: string; +} + export interface Filter { categories: string[]; - hasCommercial: boolean; - isAsyncAPIOwner: boolean; + hasCommercial?: boolean; + isAsyncAPIOwner?: boolean; language?: { name: string; color: string; borderColor: string }[]; - technology: { name: string; color: string; borderColor: string }[]; + technology?: { name: string; color: string; borderColor: string }[]; }; export interface ToolData { title: string; - description: string; - links: Link; + description?: string; + links?: Link; filters: Filter; }; @@ -24,4 +42,13 @@ export interface ToolsListType { description: string; toolsList: ToolData[]; } -} +}; + +export interface VisibleDataListType { + lang?: boolean; + tech?: boolean; + desc?: boolean; + category?: boolean; + pricing?: boolean; + ownership?: boolean; +}; From 1b70f5bfbba457e44ea84ebb8a8266b4970ab153 Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Wed, 20 Mar 2024 09:40:29 +0530 Subject: [PATCH 10/16] migrated tools dashboard --- components/tools/CategoryDropdown.tsx | 4 +- components/tools/Filters.tsx | 4 +- components/tools/ToolsDashboard.tsx | 245 +++++++++++++++++++++++++ components/tools/ToolsList.tsx | 6 +- types/components/tools/ToolDataType.ts | 8 +- 5 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 components/tools/ToolsDashboard.tsx diff --git a/components/tools/CategoryDropdown.tsx b/components/tools/CategoryDropdown.tsx index 7ec64528a8f..522bcd299f1 100644 --- a/components/tools/CategoryDropdown.tsx +++ b/components/tools/CategoryDropdown.tsx @@ -1,4 +1,4 @@ -import type { ToolsListType } from '@/types/components/tools/ToolDataType'; +import type { ToolsListData } from '@/types/components/tools/ToolDataType'; import ToolsDataList from '../../config/tools.json'; @@ -6,7 +6,7 @@ interface CategoryDropdownProps { setopenCategory: React.Dispatch>; }; -const ToolsData = ToolsDataList as ToolsListType; +const ToolsData = ToolsDataList as ToolsListData; /** * @description This component displays Category Dropdown. diff --git a/components/tools/Filters.tsx b/components/tools/Filters.tsx index 36566d1f9e6..13fac3d38fa 100644 --- a/components/tools/Filters.tsx +++ b/components/tools/Filters.tsx @@ -74,7 +74,7 @@ export default function Filters({ setOpenFilter }: FiltersProps) { // Set the params key only when the default value of the key changes. This is to know when the user actually applies filter(s). if (checkOwner) { - searchParams.set('owned', checkOwner.toString()); + searchParams.set('owned', isAsyncAPIOwner ? 'true' : 'false'); } if (checkedTechnology.length > 0) { searchParams.set('techs', checkedTechnology.join(',')); @@ -134,7 +134,7 @@ export default function Filters({ setOpenFilter }: FiltersProps) {
diff --git a/components/tools/ToolsDashboard.tsx b/components/tools/ToolsDashboard.tsx new file mode 100644 index 00000000000..56c69204325 --- /dev/null +++ b/components/tools/ToolsDashboard.tsx @@ -0,0 +1,245 @@ +import { useRouter } from 'next/router'; +import { useContext, useEffect, useRef, useState } from 'react'; + +import type { ToolsListData } from '@/types/components/tools/ToolDataType'; + +import ToolsDataList from '../../config/tools.json'; +import ToolFilter, { ToolFilterContext } from '../../context/ToolFilterContext'; +import ArrowDown from '../icons/ArrowDown'; +import Cross from '../icons/Cross'; +import FilterIcon from '../icons/Filter'; +import SearchIcon from '../icons/Search'; +import CategoryDropdown from './CategoryDropdown'; +import Filters from './Filters'; +import ToolsList from './ToolsList'; + +const ToolsData = ToolsDataList as ToolsListData; + +/** + * @description This component displays Tools Dashboard. + */ +export default function ToolsDashboard() { + const router = useRouter(); + const loader = 'img/loaders/loader.png'; // preloader image for the tools + + const [loading, setLoading] = useState(false); // used to handle the preloader on the page + const filterRef = useRef(); // used to provide ref to the Filter menu and outside click close feature + const categoryRef = useRef(); // used to provide ref to the Category menu and outside click close feature + const [openFilter, setOpenFilter] = useState(false); + const [openCategory, setopenCategory] = useState(false); + // filter parameters extracted from the context + const { isPaid, isAsyncAPIOwner, languages, technologies, categories } = useContext(ToolFilterContext); + const [searchName, setSearchName] = useState(''); // state variable used to get the search name + const [toolsList, setToolsList] = useState({}); // state variable used to set the list of tools according to the filters applied + const [checkToolsList, setCheckToolsList] = useState(true); // state variable used to check whether any tool is available according to the needs of the user. + + // useEffect function to enable the close Modal feature when clicked outside of the modal + useEffect(() => { + const checkIfClickOutside = (event: MouseEvent) => { + if (openFilter && filterRef.current && !filterRef.current.contains(event.target as Node)) { + setOpenFilter(false); + } + }; + + document.addEventListener('mousedown', checkIfClickOutside); + + return () => { + document.removeEventListener('mousedown', checkIfClickOutside); + }; + }); + + // sets the preloader on the page for 1 second + useEffect(() => { + setLoading(true); + setTimeout(() => { + setLoading(false); + }, 1000); + }, []); + + // useEffect function to enable the close Category dropdown Modal feature when clicked outside of the modal + useEffect(() => { + const checkIfClickOutside = (event: MouseEvent) => { + if (openCategory && categoryRef.current && !categoryRef.current.contains(event.target as Node)) { + setopenCategory(false); + } + }; + + document.addEventListener('mousedown', checkIfClickOutside); + + return () => { + document.removeEventListener('mousedown', checkIfClickOutside); + }; + }); + + // Function to update the list of tools according to the current filters applied + const updateToolsList = () => { + let tempToolsList: ToolsListData = {}; + + // Tools data list is first filtered according to the category filter if applied by the user. + // Hence if any category is selected, then only respective tools will be selected for further check on filters + if (categories.length > 0) { + for (const category of categories) { + // eslint-disable-next-line @typescript-eslint/no-loop-func + Object.keys(ToolsData).forEach((key) => { + if (key === category) { + tempToolsList[key] = JSON.parse(JSON.stringify(ToolsData[key])); + } + }); + } + } else { + // if no category is selected, then all tools are selected for further check on filters + tempToolsList = JSON.parse(JSON.stringify(ToolsData)); + } + + // checkToolsList is initially made false to check whether any tools are present according to the filters. + setCheckToolsList(false); + + // Each tool selected is then traversed to check against each filter variable (only if the filter is applied), + // whether they match with the filter applied or not. + Object.keys(tempToolsList).forEach((category) => { + tempToolsList[category].toolsList = tempToolsList[category].toolsList.filter((tool) => { + // These are filter check variables for respective filters, which are initially made true. + // If the particular filter is applied by the user, the respective check variable is made false first, + // and then tool parameters are checked against the filter variable value to decide if it matches the filter criteria or not. + let isLanguageTool = true; + let isTechnologyTool = true; + let isSearchTool = true; + let isAsyncAPITool = true; + let isPaidTool = true; + + if (languages.length) { + isLanguageTool = false; + for (const language of languages) { + if (tool?.filters?.language && tool.filters.language.find((item) => item.name === language)) { + isLanguageTool = true; + } + } + } + + if (technologies.length) { + isTechnologyTool = false; + for (const technology of technologies) { + if (tool?.filters?.technology && tool.filters.technology.find((item) => item.name === technology)) { + isTechnologyTool = true; + } + } + } + + if (searchName) { + isSearchTool = tool.title.toLowerCase().includes(searchName.toLowerCase()); + } + + if (isAsyncAPIOwner) { + isAsyncAPITool = tool.filters.isAsyncAPIOwner === isAsyncAPIOwner; + } + + if (isPaid !== 'all') { + if (isPaid === 'free') { + isPaidTool = tool.filters.hasCommercial === false; + } else { + isPaidTool = tool.filters.hasCommercial === true; + } + } + + return isLanguageTool && isTechnologyTool && isSearchTool && isAsyncAPITool && isPaidTool; + }); + + if (tempToolsList[category].toolsList.length) { + setCheckToolsList(true); + } + }); + + setToolsList(tempToolsList); + }; + + const clearFilters = () => { + setOpenFilter(false); + router.push('/tools', undefined, { shallow: true }); + }; + + useEffect(() => { + updateToolsList(); + }, [isPaid, isAsyncAPIOwner, languages, technologies, categories, searchName]); + + const isFiltered = Boolean(isPaid !== 'all' || isAsyncAPIOwner || languages.length || technologies.length || categories.length); + + return ( + +
+
+
+
}> +
setOpenFilter(!openFilter)} data-testid='ToolsDashboard-Filters-Click' + > + +
Filter
+
+ {openFilter && ( + + )} +
+
+
+
}> +
setopenCategory(!openCategory)} + data-testid='ToolsDashboard-category' + > +
Jump to Category
+ +
+ {openCategory && ( +
+ +
+ )} +
+
+
+ + setSearchName(e.target.value)} + /> + {searchName && ( + + )} +
+
+ {isFiltered && ( +
+ + Clear Filters +
+ )} + {loading ? ( +
+ loading +
Loading Tools...
+
+ ) : ( +
+ {checkToolsList ? ( + + ) : ( +
+ not found +
Sorry, we don't have tools according to your needs.
+
+ )} +
+ )} +
+
+ ); +}; diff --git a/components/tools/ToolsList.tsx b/components/tools/ToolsList.tsx index ec94a178c55..6f1bb4780a0 100644 --- a/components/tools/ToolsList.tsx +++ b/components/tools/ToolsList.tsx @@ -1,4 +1,4 @@ -import type { ToolsListType } from '@/types/components/tools/ToolDataType'; +import type { ToolsListData } from '@/types/components/tools/ToolDataType'; import { HeadingTypeStyle } from '@/types/typography/Heading'; import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; @@ -7,14 +7,14 @@ import Paragraph from '../typography/Paragraph'; import ToolsCard from './ToolsCard'; interface ToolsListProp { - toolsListData: ToolsListType; + toolsListData: ToolsListData; } /** * @description This component displays list of tools. * * @param {ToolsListProp} props - Props for the ToolsList component. - * @param {ToolsListType} props.toolsListData - List of Tools. + * @param {ToolsListData} props.toolsListData - List of Tools. */ export default function ToolsList({ toolsListData }: ToolsListProp) { return ( diff --git a/types/components/tools/ToolDataType.ts b/types/components/tools/ToolDataType.ts index 68995f61a8e..6479f67cc07 100644 --- a/types/components/tools/ToolDataType.ts +++ b/types/components/tools/ToolDataType.ts @@ -8,19 +8,19 @@ export interface Language { name: string; color: string; borderColor: string; -} +}; export interface Technology { name: string; color: string; borderColor: string; -} +}; export interface Category { name: string; tag: string; description: string; -} +}; export interface Filter { categories: string[]; @@ -37,7 +37,7 @@ export interface ToolData { filters: Filter; }; -export interface ToolsListType { +export interface ToolsListData { [category: string]: { description: string; toolsList: ToolData[]; From 7b05f1d133e3bb9ae78311075eb00745515ebabf Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Wed, 27 Mar 2024 10:26:52 +0530 Subject: [PATCH 11/16] incoporated review suggestions --- components/tools/CardData.tsx | 2 ++ components/tools/CategoryDropdown.tsx | 1 - components/tools/Tags.tsx | 2 +- components/tools/ToolsList.tsx | 36 ++++++++++--------- .../{categorylist.ts => categorylist.js} | 4 +-- 5 files changed, 23 insertions(+), 22 deletions(-) rename scripts/tools/{categorylist.ts => categorylist.js} (97%) diff --git a/components/tools/CardData.tsx b/components/tools/CardData.tsx index 96bdbe3d910..6071529ed4e 100644 --- a/components/tools/CardData.tsx +++ b/components/tools/CardData.tsx @@ -50,6 +50,7 @@ export const CardData = ({ }; const domNode = useRef(null); + // Decide whether to show full description or not in the card based on the number of lines occupied by the description. useEffect(() => { const divHeight = domNode.current?.offsetHeight || 0; const numberOfLines = divHeight / 20; @@ -61,6 +62,7 @@ export const CardData = ({ } }, [visible]); + // Decide whether the user click outside this component (card description) or not. useEffect(() => { const maybeHandler = (event: MouseEvent) => { setOutsideClick(true); diff --git a/components/tools/CategoryDropdown.tsx b/components/tools/CategoryDropdown.tsx index 522bcd299f1..f8b934c7f29 100644 --- a/components/tools/CategoryDropdown.tsx +++ b/components/tools/CategoryDropdown.tsx @@ -26,7 +26,6 @@ export default function CategoryDropdown({ setopenCategory }: CategoryDropdownPr {categoryName}
); } - return null; })}
diff --git a/components/tools/Tags.tsx b/components/tools/Tags.tsx index b1c9e5ccda9..0608277df7d 100644 --- a/components/tools/Tags.tsx +++ b/components/tools/Tags.tsx @@ -5,7 +5,7 @@ interface SelectTagsProps { }; /** - * @description This component displays tags. + * @description This component displays tags. These tags are displayed for languages and technologies in the tools card. * * @param {SelectTagsProps} props - The props for the Select Tags component. * @param {string} props.name - The content to be displayed inside the tag. diff --git a/components/tools/ToolsList.tsx b/components/tools/ToolsList.tsx index 6f1bb4780a0..30259a52ce0 100644 --- a/components/tools/ToolsList.tsx +++ b/components/tools/ToolsList.tsx @@ -20,24 +20,26 @@ export default function ToolsList({ toolsListData }: ToolsListProp) { return (
{Object.keys(toolsListData).map((categoryName, index) => { - if (toolsListData[categoryName].toolsList.length > 0) return ( -
- - {categoryName} - - - {toolsListData[categoryName].description} - -
-
- {toolsListData[categoryName].toolsList.map((tool, toolIndex) => ( - - ))} + if (toolsListData[categoryName].toolsList.length > 0) { + return ( +
+ + {categoryName} + + + {toolsListData[categoryName].description} + +
+
+ {toolsListData[categoryName].toolsList.map((tool, toolIndex) => ( + + ))} +
-
- ); - - return null; + ); + } else { + return null; + } })}
); diff --git a/scripts/tools/categorylist.ts b/scripts/tools/categorylist.js similarity index 97% rename from scripts/tools/categorylist.ts rename to scripts/tools/categorylist.js index 0f8d029658f..b9fe03f2904 100644 --- a/scripts/tools/categorylist.ts +++ b/scripts/tools/categorylist.js @@ -1,7 +1,5 @@ -import { Category } from "@/types/components/tools/ToolDataType"; - // Various categories to define the category in which a tool has to be listed -const categoryList: Category[] = [ +const categoryList = [ { name: "APIs", tag: "api", From 6e85813559fadfac54e3e2a6993db0a1c9339998 Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Wed, 27 Mar 2024 10:31:41 +0530 Subject: [PATCH 12/16] fixed lint issue --- components/tools/CardData.tsx | 2 +- components/tools/CategoryDropdown.tsx | 26 ++- components/tools/Filters.tsx | 168 +++++++++++++---- components/tools/FiltersDisplay.tsx | 34 ++-- components/tools/FiltersDropdown.tsx | 25 ++- components/tools/Tags.tsx | 15 +- components/tools/ToolsCard.tsx | 250 +++++++++++++++----------- components/tools/ToolsDashboard.tsx | 15 +- components/tools/ToolsList.tsx | 14 +- 9 files changed, 362 insertions(+), 187 deletions(-) diff --git a/components/tools/CardData.tsx b/components/tools/CardData.tsx index 6071529ed4e..f5ce0fbe614 100644 --- a/components/tools/CardData.tsx +++ b/components/tools/CardData.tsx @@ -14,7 +14,7 @@ interface CardDataProps { setVisible: React.Dispatch>; type: keyof VisibleDataListType; className?: string; -}; +} /** * @description This component displays Card. diff --git a/components/tools/CategoryDropdown.tsx b/components/tools/CategoryDropdown.tsx index f8b934c7f29..f865a226021 100644 --- a/components/tools/CategoryDropdown.tsx +++ b/components/tools/CategoryDropdown.tsx @@ -4,7 +4,7 @@ import ToolsDataList from '../../config/tools.json'; interface CategoryDropdownProps { setopenCategory: React.Dispatch>; -}; +} const ToolsData = ToolsDataList as ToolsListData; @@ -15,20 +15,34 @@ const ToolsData = ToolsDataList as ToolsListData; */ export default function CategoryDropdown({ setopenCategory }: CategoryDropdownProps) { return ( -
+
{Object.keys(ToolsData).map((categoryName, index) => { // displaying tools category having atleast one tool if (ToolsData[categoryName].toolsList.length > 0) { return (
setopenCategory(false)}> - {categoryName} -
); + + {categoryName} + +
+ ); } + return null; })}
); -}; +} diff --git a/components/tools/Filters.tsx b/components/tools/Filters.tsx index 13fac3d38fa..d3ef0f0e818 100644 --- a/components/tools/Filters.tsx +++ b/components/tools/Filters.tsx @@ -89,10 +89,14 @@ export default function Filters({ setOpenFilter }: FiltersProps) { searchParams.set('categories', checkedCategory.join(',')); } - router.push({ - pathname: '/tools', - query: searchParams.toString() - }, undefined, { shallow: true }); + router.push( + { + pathname: '/tools', + query: searchParams.toString() + }, + undefined, + { shallow: true } + ); }; // function to undo all the filters when `Undo Changes` is clicked. @@ -110,18 +114,34 @@ export default function Filters({ setOpenFilter }: FiltersProps) {
- +
Undo Changes
-
(checkPaid === 'free' ? setCheckPaid('all') : setCheckPaid('free'))}> +
(checkPaid === 'free' ? setCheckPaid('all') : setCheckPaid('free'))} + >
Open Source
Free
-
(checkPaid === 'paid' ? setCheckPaid('all') : setCheckPaid('paid'))}> +
(checkPaid === 'paid' ? setCheckPaid('all') : setCheckPaid('paid'))} + >
Commercial
Paid
@@ -130,66 +150,150 @@ export default function Filters({ setOpenFilter }: FiltersProps) {
- +
-
- Show only AsyncAPI-owned tools -
+
Show only AsyncAPI-owned tools

- +
-
setopenLanguage(!openLanguage)}> +
setopenLanguage(!openLanguage)} + >
{/* eslint-disable-next-line no-nested-ternary */} - {checkedLanguage.length > 0 ? (checkedLanguage.length === 1 ? '1 option selected' : `${checkedLanguage.length} options selected`) : 'Select Languages...'} + {checkedLanguage.length > 0 + ? checkedLanguage.length === 1 + ? '1 option selected' + : `${checkedLanguage.length} options selected` + : 'Select Languages...'}
- {openLanguage &&
- -
} + {openLanguage && ( +
+ +
+ )}

- +
-
setopenTechnology(!openTechnology)}> +
setopenTechnology(!openTechnology)} + >
{/* eslint-disable-next-line no-nested-ternary */} - {checkedTechnology.length > 0 ? (checkedTechnology.length === 1 ? '1 option selected' : `${checkedTechnology.length} options selected`) : 'Select Technologies...'} + {checkedTechnology.length > 0 + ? checkedTechnology.length === 1 + ? '1 option selected' + : `${checkedTechnology.length} options selected` + : 'Select Technologies...'}
- {openTechnology &&
- -
} + {openTechnology && ( +
+ +
+ )}

- +
-
setopenCategory(!openCategory)}> +
setopenCategory(!openCategory)} + >
{/* eslint-disable-next-line no-nested-ternary */} - {checkedCategory.length > 0 ? (checkedCategory.length === 1 ? '1 option selected' : `${checkedCategory.length} options selected`) : 'Select Categories...'} + {checkedCategory.length > 0 + ? checkedCategory.length === 1 + ? '1 option selected' + : `${checkedCategory.length} options selected` + : 'Select Categories...'}
- {openCategory &&
- -
} + {openCategory && ( +
+ +
+ )}
@@ -200,4 +304,4 @@ export default function Filters({ setOpenFilter }: FiltersProps) {
); -}; +} diff --git a/components/tools/FiltersDisplay.tsx b/components/tools/FiltersDisplay.tsx index e79ff3c5e7c..945481cae24 100644 --- a/components/tools/FiltersDisplay.tsx +++ b/components/tools/FiltersDisplay.tsx @@ -3,7 +3,7 @@ import { twMerge } from 'tailwind-merge'; interface FiltersDisplayProps { checkedOptions?: string[]; setCheckedOptions: React.Dispatch>; -}; +} /** * @description This component displays Filters. @@ -11,12 +11,14 @@ interface FiltersDisplayProps { * @param {string[]} props.checkedOptions - List of options that are currently checked. * @param {React.Dispatch>} props.setCheckedOptions - Function to set check state of options. */ -export default function FiltersDisplay({ - checkedOptions = [], - setCheckedOptions -}: FiltersDisplayProps) { +export default function FiltersDisplay({ checkedOptions = [], setCheckedOptions }: FiltersDisplayProps) { // function to clear selected filters - const handleClickOption = (event: React.MouseEvent, option: string, checkedOptionsList: typeof checkedOptions, setCheckedOptionsList: typeof setCheckedOptions) => { + const handleClickOption = ( + event: React.MouseEvent, + option: string, + checkedOptionsList: typeof checkedOptions, + setCheckedOptionsList: typeof setCheckedOptions + ) => { const tempValueArray = [...checkedOptionsList]; const index = checkedOptionsList.indexOf(option); @@ -28,21 +30,29 @@ export default function FiltersDisplay({ return ( <> - {checkedOptions.length > 0 && + {checkedOptions.length > 0 && (
{checkedOptions.map((items, index) => { return (
{items}
- +
); })} -
} +
+ )} ); -}; +} diff --git a/components/tools/FiltersDropdown.tsx b/components/tools/FiltersDropdown.tsx index 561e90d2c38..fbf2d5c7a20 100644 --- a/components/tools/FiltersDropdown.tsx +++ b/components/tools/FiltersDropdown.tsx @@ -9,7 +9,7 @@ interface FiltersDropdownProps { checkedOptions?: string[]; setCheckedOptions: React.Dispatch>; className?: string; -}; +} /** * @description This component displays Filter Dropdown Component. @@ -27,29 +27,36 @@ export default function FiltersDropdown({ }: FiltersDropdownProps) { const handleClickOption = (event: React.MouseEvent, option: string) => { const isChecked = checkedOptions.includes(option); - const updatedOptions = isChecked - ? checkedOptions.filter(item => item !== option) - : [...checkedOptions, option]; + const updatedOptions = isChecked ? checkedOptions.filter((item) => item !== option) : [...checkedOptions, option]; setCheckedOptions(updatedOptions); }; return ( -
+
{dataList.map((data, index) => { const checked = checkedOptions.includes(data.name); return (
handleClickOption(event, data.name)} > - {checked ? checked : unchecked} -
{data.name}
+ {checked ? ( + checked + ) : ( + unchecked + )} +
{data.name}
); })}
); -}; +} diff --git a/components/tools/Tags.tsx b/components/tools/Tags.tsx index 0608277df7d..a24c07ace58 100644 --- a/components/tools/Tags.tsx +++ b/components/tools/Tags.tsx @@ -2,7 +2,7 @@ interface SelectTagsProps { name?: string; bgColor: string; borderColor: string; -}; +} /** * @description This component displays tags. These tags are displayed for languages and technologies in the tools card. @@ -12,14 +12,13 @@ interface SelectTagsProps { * @param {string} props.bgColor - The color of the tag. * @param {string} props.borderColor - The border color of the tag. */ -export default function SelectTags({ - name = '', - bgColor, - borderColor -} : SelectTagsProps) { +export default function SelectTags({ name = '', bgColor, borderColor }: SelectTagsProps) { return ( -
+
{name}
); -}; +} diff --git a/components/tools/ToolsCard.tsx b/components/tools/ToolsCard.tsx index 333f33830a6..7a724f6a391 100644 --- a/components/tools/ToolsCard.tsx +++ b/components/tools/ToolsCard.tsx @@ -35,7 +35,7 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { setShowMoreDescription(true); } else { setShowMoreDescription(false); - }; + } }, []); let onGit = false; @@ -64,135 +64,175 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { {toolData.title}
(setTimeout(() => { if (!visible.desc) setVisible({ ...visible, desc: true }); }, 400))} + onMouseEnter={() => + setTimeout(() => { + if (!visible.desc) setVisible({ ...visible, desc: true }); + }, 400) + } > (setTimeout(() => { if (visible.desc) setVisible({ ...visible, desc: false }); }, 300))} + onMouseLeave={() => + setTimeout(() => { + if (visible.desc) setVisible({ ...visible, desc: false }); + }, 300) + } > {toolData.filters?.hasCommercial === false ? 'Open Source' : 'Commercial'} - {visible.desc && - {Data.properties.filters.properties.hasCommercial.description} - } + {visible.desc && ( + + {Data.properties.filters.properties.hasCommercial.description} + + )}
-
(setTimeout(() => { if (showMoreDescription) setShowDescription(true); }, 500))}> -
+
+ setTimeout(() => { + if (showMoreDescription) setShowDescription(true); + }, 500) + } + > + +
- {showDescription &&
(setShowDescription(false))}> - - {toolData.description} - -
} + {showDescription && ( +
setShowDescription(false)} + > + + {toolData.description} + +
+ )}

- {(toolData.filters?.language || toolData?.filters?.technology?.length) ?
- {toolData.filters.language &&
- + {toolData.filters.language && ( +
+ -
- {toolData.filters?.language && toolData.filters?.language.map((item, index) => ( - - ))} -
-
} - {toolData.filters?.technology?.length &&
- -
- {toolData.filters?.technology && toolData.filters.technology.map((item, index) => ( - + {toolData.filters?.language && + toolData.filters?.language.map((item, index) => ( + + ))} +
+
+ )} + {toolData.filters?.technology?.length && ( +
+ - ))} -
-
} -
: +
+ {toolData.filters?.technology && + toolData.filters.technology.map((item, index) => ( + + ))} +
+
+ )} +
+ ) : (
-
No further details provided
-
} +
+ {' '} + No further details provided{' '} +
+
+ )}
- {(toolData?.links?.repoUrl || toolData?.links?.websiteUrl || toolData?.links?.docsUrl) && <> -
-
- {toolData.links.repoUrl && <> - {onGit ? - + {(toolData?.links?.repoUrl || toolData?.links?.websiteUrl || toolData?.links?.docsUrl) && ( + <> +
+
+ {toolData.links.repoUrl && ( + <> + {onGit ? ( + +
+ GitHub +
View Github
+
+
+ ) : ( + +
+
View Source Code
+
+
+ )} + + )} + {toolData.links.websiteUrl && ( +
- GitHub -
View Github
+ Share +
Visit Website
-
: - + + )} + {toolData.links.docsUrl && ( +
-
View Source Code
+ Docs +
Visit Docs
- } - } - {toolData.links.websiteUrl && ( - -
- Share -
Visit Website
-
-
- )} - {toolData.links.docsUrl && ( - -
- Docs -
Visit Docs
-
-
- )} -
- } + )} +
+ + )}
); -}; +} diff --git a/components/tools/ToolsDashboard.tsx b/components/tools/ToolsDashboard.tsx index 56c69204325..da74ade22ed 100644 --- a/components/tools/ToolsDashboard.tsx +++ b/components/tools/ToolsDashboard.tsx @@ -161,7 +161,9 @@ export default function ToolsDashboard() { updateToolsList(); }, [isPaid, isAsyncAPIOwner, languages, technologies, categories, searchName]); - const isFiltered = Boolean(isPaid !== 'all' || isAsyncAPIOwner || languages.length || technologies.length || categories.length); + const isFiltered = Boolean( + isPaid !== 'all' || isAsyncAPIOwner || languages.length || technologies.length || categories.length + ); return ( @@ -171,7 +173,8 @@ export default function ToolsDashboard() {
}>
setOpenFilter(!openFilter)} data-testid='ToolsDashboard-Filters-Click' + onClick={() => setOpenFilter(!openFilter)} + data-testid='ToolsDashboard-Filters-Click' >
Filter
@@ -200,7 +203,7 @@ export default function ToolsDashboard() { )}
-
+
{isFiltered && ( -
+
- Clear Filters + Clear Filters
)} {loading ? ( @@ -242,4 +245,4 @@ export default function ToolsDashboard() {
); -}; +} diff --git a/components/tools/ToolsList.tsx b/components/tools/ToolsList.tsx index 30259a52ce0..621e16400f8 100644 --- a/components/tools/ToolsList.tsx +++ b/components/tools/ToolsList.tsx @@ -18,17 +18,15 @@ interface ToolsListProp { */ export default function ToolsList({ toolsListData }: ToolsListProp) { return ( -
+
{Object.keys(toolsListData).map((categoryName, index) => { if (toolsListData[categoryName].toolsList.length > 0) { return (
- + {categoryName} - - {toolsListData[categoryName].description} - + {toolsListData[categoryName].description}
{toolsListData[categoryName].toolsList.map((tool, toolIndex) => ( @@ -37,10 +35,10 @@ export default function ToolsList({ toolsListData }: ToolsListProp) {
); - } else { - return null; } + + return null; })}
); -}; +} From 911b3729e17c2b083c0cfc44b7e67c37838da4ea Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Wed, 27 Mar 2024 12:28:37 +0530 Subject: [PATCH 13/16] added comments: --- components/tools/ToolsCard.tsx | 174 +++++++++++++++++++++------------ 1 file changed, 109 insertions(+), 65 deletions(-) diff --git a/components/tools/ToolsCard.tsx b/components/tools/ToolsCard.tsx index 7a724f6a391..ccac6654a36 100644 --- a/components/tools/ToolsCard.tsx +++ b/components/tools/ToolsCard.tsx @@ -1,7 +1,10 @@ import { useEffect, useRef, useState } from 'react'; import TextTruncate from 'react-text-truncate'; -import type { ToolData, VisibleDataListType } from '@/types/components/tools/ToolDataType'; +import type { + ToolData, + VisibleDataListType, +} from '@/types/components/tools/ToolDataType'; import { HeadingTypeStyle } from '@/types/typography/Heading'; import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; @@ -23,10 +26,12 @@ interface ToolsCardProp { */ export default function ToolsCard({ toolData }: ToolsCardProp) { const [showDescription, setShowDescription] = useState(false); - const [showMoreDescription, setShowMoreDescription] = useState(false); + const [showMoreDescription, setShowMoreDescription] = + useState(false); const [readMore, setReadMore] = useState(false); const descriptionRef = useRef(null); + // Decide whether to show full description or not in the card based on the number of lines occupied by the description. useEffect(() => { const divHeight = descriptionRef.current?.offsetHeight || 0; const numberOfLines = divHeight / 20; @@ -53,17 +58,19 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { const [visible, setVisible] = useState({ lang: false, tech: false, - desc: false + desc: false, }); return ( -
-
-
-
- {toolData.title} +
+
+
+
+ + {toolData.title} +
setTimeout(() => { if (!visible.desc) setVisible({ ...visible, desc: true }); @@ -71,23 +78,28 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { } > setTimeout(() => { if (visible.desc) setVisible({ ...visible, desc: false }); }, 300) } > - {toolData.filters?.hasCommercial === false ? 'Open Source' : 'Commercial'} + {toolData.filters?.hasCommercial === false + ? 'Open Source' + : 'Commercial'} {visible.desc && ( - - {Data.properties.filters.properties.hasCommercial.description} + + { + Data.properties.filters.properties.hasCommercial + .description + } )}
-
+
- +
{showDescription && (
setShowDescription(false)} > - + {toolData.description}
@@ -114,89 +130,109 @@ export default function ToolsCard({ toolData }: ToolsCardProp) {
-
-
+
+
{toolData.filters?.language || toolData?.filters?.technology?.length ? ( -
+
{toolData.filters.language && ( -
+
-
+
{toolData.filters?.language && toolData.filters?.language.map((item, index) => ( - + ))}
)} {toolData.filters?.technology?.length && ( -
+
-
+
{toolData.filters?.technology && toolData.filters.technology.map((item, index) => ( - + ))}
)}
) : ( -
-
+
+
{' '} No further details provided{' '}
)}
- {(toolData?.links?.repoUrl || toolData?.links?.websiteUrl || toolData?.links?.docsUrl) && ( + {(toolData?.links?.repoUrl || + toolData?.links?.websiteUrl || + toolData?.links?.docsUrl) && ( <> -
-
+
+
{toolData.links.repoUrl && ( <> {onGit ? ( -
- GitHub -
View Github
+
+ GitHub +
View Github
) : ( -
-
View Source Code
+
+
+ View Source Code +
)} @@ -204,29 +240,37 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { )} {toolData.links.websiteUrl && ( -
- Share -
Visit Website
+
+ Share +
Visit Website
)} {toolData.links.docsUrl && ( -
- Docs -
Visit Docs
+
+ Docs +
Visit Docs
)} From 84ab865c7fe3e98c9c65014b58d7f3c3c2062c4e Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Wed, 27 Mar 2024 12:36:59 +0530 Subject: [PATCH 14/16] fix lint issue --- components/tools/ToolsCard.tsx | 173 +++++++++++++-------------------- 1 file changed, 65 insertions(+), 108 deletions(-) diff --git a/components/tools/ToolsCard.tsx b/components/tools/ToolsCard.tsx index ccac6654a36..eec4062c4c5 100644 --- a/components/tools/ToolsCard.tsx +++ b/components/tools/ToolsCard.tsx @@ -1,10 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import TextTruncate from 'react-text-truncate'; -import type { - ToolData, - VisibleDataListType, -} from '@/types/components/tools/ToolDataType'; +import type { ToolData, VisibleDataListType } from '@/types/components/tools/ToolDataType'; import { HeadingTypeStyle } from '@/types/typography/Heading'; import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; @@ -26,8 +23,7 @@ interface ToolsCardProp { */ export default function ToolsCard({ toolData }: ToolsCardProp) { const [showDescription, setShowDescription] = useState(false); - const [showMoreDescription, setShowMoreDescription] = - useState(false); + const [showMoreDescription, setShowMoreDescription] = useState(false); const [readMore, setReadMore] = useState(false); const descriptionRef = useRef(null); @@ -58,19 +54,17 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { const [visible, setVisible] = useState({ lang: false, tech: false, - desc: false, + desc: false }); return ( -
-
-
-
- - {toolData.title} - +
+
+
+
+ {toolData.title}
setTimeout(() => { if (!visible.desc) setVisible({ ...visible, desc: true }); @@ -78,28 +72,23 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { } > setTimeout(() => { if (visible.desc) setVisible({ ...visible, desc: false }); }, 300) } > - {toolData.filters?.hasCommercial === false - ? 'Open Source' - : 'Commercial'} + {toolData.filters?.hasCommercial === false ? 'Open Source' : 'Commercial'} {visible.desc && ( - - { - Data.properties.filters.properties.hasCommercial - .description - } + + {Data.properties.filters.properties.hasCommercial.description} )}
-
+
- +
{showDescription && (
setShowDescription(false)} > - + {toolData.description}
@@ -130,109 +115,89 @@ export default function ToolsCard({ toolData }: ToolsCardProp) {
-
-
+
+
{toolData.filters?.language || toolData?.filters?.technology?.length ? ( -
+
{toolData.filters.language && ( -
+
-
+
{toolData.filters?.language && toolData.filters?.language.map((item, index) => ( - + ))}
)} {toolData.filters?.technology?.length && ( -
+
-
+
{toolData.filters?.technology && toolData.filters.technology.map((item, index) => ( - + ))}
)}
) : ( -
-
+
+
{' '} No further details provided{' '}
)}
- {(toolData?.links?.repoUrl || - toolData?.links?.websiteUrl || - toolData?.links?.docsUrl) && ( + {(toolData?.links?.repoUrl || toolData?.links?.websiteUrl || toolData?.links?.docsUrl) && ( <> -
-
+
+
{toolData.links.repoUrl && ( <> {onGit ? ( -
- GitHub -
View Github
+
+ GitHub +
View Github
) : ( -
-
- View Source Code -
+
+
View Source Code
)} @@ -240,37 +205,29 @@ export default function ToolsCard({ toolData }: ToolsCardProp) { )} {toolData.links.websiteUrl && ( -
- Share -
Visit Website
+
+ Share +
Visit Website
)} {toolData.links.docsUrl && ( -
- Docs -
Visit Docs
+
+ Docs +
Visit Docs
)} From 89304b6563cfbcfa4def1f1e075d45a58ad1deab Mon Sep 17 00:00:00 2001 From: devilkiller-ag Date: Fri, 29 Mar 2024 13:07:24 +0530 Subject: [PATCH 15/16] restored the original categorylist in scripts/tool --- scripts/tools/categorylist.js | 116 +++++++++++++++++----------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/scripts/tools/categorylist.js b/scripts/tools/categorylist.js index b9fe03f2904..11fcc3790e9 100644 --- a/scripts/tools/categorylist.js +++ b/scripts/tools/categorylist.js @@ -1,100 +1,100 @@ // Various categories to define the category in which a tool has to be listed const categoryList = [ { - name: "APIs", - tag: "api", - description: "The following is a list of APIs that expose functionality related to AsyncAPI." + name: "APIs", + tag: "api", + description: "The following is a list of APIs that expose functionality related to AsyncAPI." }, { - name: "Code-first tools", - tag: "code-first", - description: "The following is a list of tools that generate AsyncAPI documents from your code." + name: "Code-first tools", + tag: "code-first", + description: "The following is a list of tools that generate AsyncAPI documents from your code." }, { - name: "Code Generators", - tag: "code-generator", - description: "The following is a list of tools that generate code from an AsyncAPI document; not the other way around." + name: "Code Generators", + tag: "code-generator", + description: "The following is a list of tools that generate code from an AsyncAPI document; not the other way around." }, { - name: "Converters", - tag: "converter", - description: "The following is a list of tools that do not yet belong to any specific category but are also useful for the community." + name: "Converters", + tag: "converter", + description: "The following is a list of tools that do not yet belong to any specific category but are also useful for the community." }, { - name: "Directories", - tag: "directory", - description: "The following is a list of directories that index public AsyncAPI documents." + name: "Directories", + tag: "directory", + description: "The following is a list of directories that index public AsyncAPI documents." }, { - name: "Documentation Generators", - tag: "documentation-generator", - description: "The following is a list of tools that generate human-readable documentation from an AsyncAPI document." + name: "Documentation Generators", + tag: "documentation-generator", + description: "The following is a list of tools that generate human-readable documentation from an AsyncAPI document." }, { - name: "Editors", - tag: "editor", - description: "The following is a list of editors or related tools that allow editing of AsyncAPI document." + name: "Editors", + tag: "editor", + description: "The following is a list of editors or related tools that allow editing of AsyncAPI document." }, { - name: "UI components", - tag: "ui-component", - description: "The following is a list of UI components to view AsyncAPI documents." + name: "UI components", + tag: "ui-component", + description: "The following is a list of UI components to view AsyncAPI documents." }, { - name: "DSL", - tag: "dsl", - description: "Writing YAML by hand is no fun, and maybe you don't want a GUI, so use a Domain Specific Language to write AsyncAPI in your language of choice." + name: "DSL", + tag: "dsl", + description: "Writing YAML by hand is no fun, and maybe you don't want a GUI, so use a Domain Specific Language to write AsyncAPI in your language of choice." }, { - name: "Frameworks", - tag: "framework", - description: "The following is a list of API/application frameworks that make use of AsyncAPI." + name: "Frameworks", + tag: "framework", + description: "The following is a list of API/application frameworks that make use of AsyncAPI." }, { - name: "GitHub Actions", - tag: "github-action", - description: "The following is a list of GitHub Actions that you can use in your workflows" + name: "GitHub Actions", + tag: "github-action", + description: "The following is a list of GitHub Actions that you can use in your workflows" }, { - name: "Mocking and Testing", - tag: "mocking-and-testing", - description: "The tools below take specification documents as input, then publish fake messages to broker destinations for simulation purposes. They may also check that publisher messages are compliant with schemas." + name: "Mocking and Testing", + tag: "mocking-and-testing", + description: "The tools below take specification documents as input, then publish fake messages to broker destinations for simulation purposes. They may also check that publisher messages are compliant with schemas." }, { - name: "Validators", - tag: "validator", - description: "The following is a list of tools that validate AsyncAPI documents." + name: "Validators", + tag: "validator", + description: "The following is a list of tools that validate AsyncAPI documents." }, { - name: "Compare tools", - tag: "compare-tool", - description: "The following is a list of tools that compare AsyncAPI documents." + name: "Compare tools", + tag: "compare-tool", + description: "The following is a list of tools that compare AsyncAPI documents." }, { - name: "CLIs", - tag: "cli", - description: "The following is a list of tools that you can work with in terminal or do some CI/CD automation." + name: "CLIs", + tag: "cli", + description: "The following is a list of tools that you can work with in terminal or do some CI/CD automation." }, { - name: "Bundlers", - tag: "bundler", - description: "The following is a list of tools that you can work with to bundle AsyncAPI documents." + name: "Bundlers", + tag: "bundler", + description: "The following is a list of tools that you can work with to bundle AsyncAPI documents." }, { - name: "IDE Extensions", - tag: "ide-extension", - description: "The following is a list of extensions for different IDEs like VSCode, IntelliJ IDEA and others" + name: "IDE Extensions", + tag: "ide-extension", + description: "The following is a list of extensions for different IDEs like VSCode, IntelliJ IDEA and others" }, { - name: "AsyncAPI Generator Templates", - tag: "generator-template", - description: "The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents." + name: "AsyncAPI Generator Templates", + tag: "generator-template", + description: "The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents." }, { - name: "Others", - tag: "other", - description: "The following is a list of tools that comes under Other category." + name: "Others", + tag: "other", + description: "The following is a list of tools that comes under Other category." } ] -export default categoryList; +module.exports = {categoryList} From 6c5bd6fffed7316ce14927d5661b3f1a2bfc324e Mon Sep 17 00:00:00 2001 From: akshatnema Date: Fri, 29 Mar 2024 22:15:19 +0530 Subject: [PATCH 16/16] Updated import --- components/tools/Filters.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/tools/Filters.tsx b/components/tools/Filters.tsx index d3ef0f0e818..4f956dca53e 100644 --- a/components/tools/Filters.tsx +++ b/components/tools/Filters.tsx @@ -6,7 +6,7 @@ import type { Language, Technology, VisibleDataListType } from '@/types/componen import tags from '../../config/all-tags.json'; import ToolFilter, { ToolFilterContext } from '../../context/ToolFilterContext'; -import categoryList from '../../scripts/tools/categorylist'; +import { categoryList } from '../../scripts/tools/categorylist'; import Data from '../../scripts/tools/tools-schema.json'; import Button from '../buttons/Button'; import ArrowDown from '../icons/ArrowDown';