From 7e371ba15b0ab9d54dfb315bd0753f138a790f4c Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:53:06 +0530 Subject: [PATCH 01/15] feat: add new react-share dependenci Signed-off-by: Amit Amrutiya --- package-lock.json | 82 ++++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 +- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bee091161..0034a3902 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "0.14.11", "dependencies": { "js-yaml": "^4.1.0", - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "react-share": "^5.1.0" }, "devDependencies": { "@commitlint/cli": "^17.7.2", @@ -4411,6 +4412,12 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -8893,6 +8900,29 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", + "integrity": "sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==", + "dependencies": { + "debug": "^2.1.3" + } + }, + "node_modules/jsonp/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/jsonp/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -11623,6 +11653,19 @@ } } }, + "node_modules/react-share": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-share/-/react-share-5.1.0.tgz", + "integrity": "sha512-OvyfMtj/0UzH1wi90OdHhZVJ6WUC/+IeWvBwppeZozwIGyAjQgyR0QXlHOrxVHVECqnGvcpBaFTXVrqouTieaw==", + "license": "MIT", + "dependencies": { + "classnames": "^2.3.2", + "jsonp": "^0.2.1" + }, + "peerDependencies": { + "react": "^17 || ^18" + } + }, "node_modules/react-sortable-tree-patch-react-17": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/react-sortable-tree-patch-react-17/-/react-sortable-tree-patch-react-17-2.9.0.tgz", @@ -17258,6 +17301,11 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -20386,6 +20434,29 @@ "universalify": "^2.0.0" } }, + "jsonp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", + "integrity": "sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==", + "requires": { + "debug": "^2.1.3" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -22192,6 +22263,15 @@ "use-sync-external-store": "^1.0.0" } }, + "react-share": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-share/-/react-share-5.1.0.tgz", + "integrity": "sha512-OvyfMtj/0UzH1wi90OdHhZVJ6WUC/+IeWvBwppeZozwIGyAjQgyR0QXlHOrxVHVECqnGvcpBaFTXVrqouTieaw==", + "requires": { + "classnames": "^2.3.2", + "jsonp": "^0.2.1" + } + }, "react-sortable-tree-patch-react-17": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/react-sortable-tree-patch-react-17/-/react-sortable-tree-patch-react-17-2.9.0.tgz", diff --git a/package.json b/package.json index 55ac382ab..04cee394a 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ }, "dependencies": { "js-yaml": "^4.1.0", - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "react-share": "^5.1.0" } } From 00810e9a6afb2d7a3a50c3d7295b2cbe416c4c78 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:53:23 +0530 Subject: [PATCH 02/15] feat: Add helper functions and types for CatalogDetail component Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/helper.ts | 75 ++++++++++++++++++++++++++++++ src/custom/CatalogDetail/types.ts | 50 ++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/custom/CatalogDetail/helper.ts create mode 100644 src/custom/CatalogDetail/types.ts diff --git a/src/custom/CatalogDetail/helper.ts b/src/custom/CatalogDetail/helper.ts new file mode 100644 index 000000000..a46311c41 --- /dev/null +++ b/src/custom/CatalogDetail/helper.ts @@ -0,0 +1,75 @@ +import jsyaml from 'js-yaml'; +import { CommunityClassIcon, OfficialClassIcon, VerificationClassIcon } from '../../icons'; +import { ContentClassType } from './types'; + +export const downloadYaml = (filteredData: string, itemName: string): void => { + const yamlData = Array.isArray(filteredData) + ? jsyaml.dump(filteredData.find((item) => item.name === itemName)) + : filteredData; + const blob = new Blob([yamlData], { type: 'application/yaml' }); + const url = URL.createObjectURL(blob); + const element = document.createElement('a'); + element.href = url; + element.download = `${itemName}.yaml`; + // document.body.appendChild(element); // Required for this to work in FireFox + element.click(); + URL.revokeObjectURL(url); +}; + +export function slugify(str: string): string { + if (!str) return str; + str = str.replace(/^\s+|\s+$/g, ''); // trim leading/trailing whitespace + str = str.toLowerCase(); + + // remove accents, swap ñ for n, etc + const from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;'; + const to = 'aaaaeeeeiiiioooouuuunc------'; + for (let i = 0, l = from.length; i < l; i++) { + str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i)); + } + + str = str + .replace(/[^a-z0-9 -]/g, '') // remove invalid chars + .replace(/\s+/g, '-') // collapse whitespace and replace by - + .replace(/-+/g, '-'); // collapse dashes + + return str; +} + +export const downloadFilter = (id: string, name: string): void => { + const dataUri = `${process.env.API_ENDPOINT_PREFIX}/api/content/filters/download/${id}`; + + // Add the .wasm extension to the filename + const fileNameWithExtension = name + '.wasm'; + + const linkElement = document.createElement('a'); + linkElement.setAttribute('href', dataUri); + linkElement.setAttribute('download', fileNameWithExtension); + linkElement.click(); + linkElement.remove(); +}; + +export const CONTENT_CLASS: ContentClassType = { + community: { + icon: CommunityClassIcon + }, + official: { + icon: OfficialClassIcon + }, + verified: { + icon: VerificationClassIcon + } +}; + +export const formatToTitleCase = (value: string): string => { + if (typeof value === 'string') { + return value.substring(0, 1).toUpperCase().concat('', value.substring(1).toLowerCase()); + } + return ''; +}; + +export const formatDate = (date: Date) => { + const options = { year: 'numeric', month: 'short', day: 'numeric' }; + const formattedDate = new Date(date).toLocaleDateString('en-US', options); + return formattedDate; +}; diff --git a/src/custom/CatalogDetail/types.ts b/src/custom/CatalogDetail/types.ts new file mode 100644 index 000000000..40d8b2d38 --- /dev/null +++ b/src/custom/CatalogDetail/types.ts @@ -0,0 +1,50 @@ +export interface User { + id: string; + first_name: string; + last_name: string; +} + +export interface FilteredAcademyData { + 'learning-path'?: string[]; + challenge?: string[]; + challenges?: string[]; +} + +export interface Class { + class: string; + description: string; +} + +export interface Theme { + palette: { + background: { + secondary: string; + inverse: string; + cta: { + default: string; + }; + }; + icon: { + default: string; + secondary: string; + }; + }; +} + +export const RESOURCE_TYPES = { + DESIGNS: 'design', + FILTERS: 'filter', + VIEWS: 'view' +}; + +export type ContentClassType = { + community: { + icon: React.ComponentType; + }; + official: { + icon: React.ComponentType; + }; + verified: { + icon: React.ComponentType; + }; +}; From 47eb5da1a415757e01f882eee6c29722d97166bd Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:54:15 +0530 Subject: [PATCH 03/15] feat: Add styles and components for CatalogDetail page Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/index.tsx | 31 ++++ src/custom/CatalogDetail/style.tsx | 252 +++++++++++++++++++++++++++++ src/custom/index.tsx | 1 + 3 files changed, 284 insertions(+) create mode 100644 src/custom/CatalogDetail/index.tsx create mode 100644 src/custom/CatalogDetail/style.tsx diff --git a/src/custom/CatalogDetail/index.tsx b/src/custom/CatalogDetail/index.tsx new file mode 100644 index 000000000..87a3d0208 --- /dev/null +++ b/src/custom/CatalogDetail/index.tsx @@ -0,0 +1,31 @@ +import ActionButtons from './ActionButton'; +import CaveatsSection from './CaveatsSection'; +import ChallengesSection from './ChallengesSection'; +import CollapsibleSection from './CollapsibleSection'; +import LearningSection from './LearningSection'; +import LeftPanel from './LeftPanel'; +import MetricsDisplay from './MetricsDisplay'; +import OverviewSection from './OverviewSection'; +import PatternInfo from './PatternInfo'; +import RelatedDesigns from './RelatedDesigns'; +import RightPanel from './RightPanel'; +import SocialSharePopper from './SocialSharePopper'; +import TechnologySection from './TechnologySection'; +import UserInfo from './UserInfo'; + +export { + ActionButtons, + CaveatsSection, + ChallengesSection, + CollapsibleSection, + LearningSection, + LeftPanel, + MetricsDisplay, + OverviewSection, + PatternInfo, + RelatedDesigns, + RightPanel, + SocialSharePopper, + TechnologySection, + UserInfo +}; diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx new file mode 100644 index 000000000..19e91d765 --- /dev/null +++ b/src/custom/CatalogDetail/style.tsx @@ -0,0 +1,252 @@ +import { ListItemButton, Paper, Typography } from '../../base'; +import { styled } from '../../theme'; +import { Theme } from './types'; + +export const StyledActionWrapper = styled(Paper)(() => ({ + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + justifyContent: 'center', + width: '100%', + margin: '0', + marginTop: '1rem', + display: 'flex', + flexDirection: 'column', + gap: '1rem', + padding: '0.6rem', + alignItems: 'center' +})); + +export const LinkUrl = styled('a')(() => ({ + textDecoration: 'none' +})); + +interface ActionButtonProps { + disabled?: boolean; + theme?: Theme; +} + +export const ActionButton = styled('div')(({ disabled = false, theme }) => ({ + cursor: disabled ? 'not-allowed' : 'pointer', + opacity: disabled ? '0.5' : '1', + textAlign: 'center', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + borderRadius: '0.5rem', + backgroundColor: theme.palette.background.brand?.default, + padding: '0.5rem', + color: theme.palette.text.inverse, + gap: '0.625rem', + flex: '1' +})); + +export const ContentDetailsText = styled(Typography)(({ theme }) => ({ + fontSize: '1rem', + color: theme.palette.text.default, + ['@media (min-width:1200px)']: { + fontSize: '1.3rem' + } +})); + +export const ContentHeading = styled('div')(() => ({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + marginBottom: '1rem' +})); + +export const CaveatsContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + textAlign: 'left', + justifyContent: 'start', + alignItems: 'start', + display: 'flex', + flexWrap: 'wrap', + flexDirection: 'column', + padding: '1.5rem', + marginTop: '1.5rem', + borderRadius: '0.4rem', + overflowWrap: 'anywhere' +})); + +interface LabelDivProps { + clickable?: boolean; +} + +export const LabelDiv = styled('div')(({ theme, clickable }) => ({ + display: 'flex', + justifyContent: 'start', + alignItems: 'center', + padding: '0.5rem 1.5rem', + width: '100%', + borderBottom: `1px solid ${theme.palette.border.default}`, + [' @media (min-width: 600px) and (max-width: 800px)']: { + padding: '0.5rem' + }, + ...(clickable && { + '&:hover': { + backgroundColor: theme.palette.background.hover + }, + cursor: 'pointer' + }) +})); + +export const SideContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + justifyContent: 'start', + alignItems: 'start', + display: 'flex', + flexDirection: 'column', + padding: '0.5rem', + borderRadius: '0.4rem' +})); + +export const SideTitleButton = styled(ListItemButton)(({ theme }) => ({ + backgroundColor: theme.palette.background.surfaces, + borderRadius: '0.5rem', + marginTop: 2, + width: '100%', + [' @media (min-width: 600px) and (max-width: 800px)']: { + padding: '0.5rem' + } +})); + +export const ContentDetailsPoints = styled(Typography)(() => ({ + fontSize: '.9rem', + fontWeight: 'bold', + lineHeight: '1.5rem', + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + gap: '1rem' +})); + +export const MetricsSection = styled('div')(() => ({ + padding: '1.1rem', + marginTop: '0.5rem', + display: 'flex', + borderTop: '0.5px solid #3C494F', + justifyContent: 'center', + gap: '1.7rem', + flexWrap: 'wrap', + ['@media (max-width:1200px)']: { + justifyContent: 'flex-start' + } +})); + +export const MetricsContainer = styled('div')(() => ({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + [' @media (min-width: 280px) and (max-width: 700px)']: { + flexBasis: '35%' + }, + [' @media (max-width: 280px)']: { + flexBasis: '10%' + } +})); +export const MetricsType = styled('div')(({ theme }) => ({ + display: 'flex', + fontSize: '16px', + fontWeight: '400', + letterSpacing: '0.15px', + lineHeight: '1.5', + textTransform: 'lowercase', + color: theme.palette.background.supplementary, + [' @media (max-width: 285px)']: { + fontSize: '0.86rem' + } +})); +export const MetricsData = styled('div')(({ theme }) => ({ + color: theme.palette.background.supplementary, + fontSize: '1.2rem', + fontWeight: 'bold', + lineHeight: '1.5' +})); + +export const OverviewContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + textAlign: 'left', + justifyContent: 'start', + alignItems: 'start', + display: 'flex', + flexWrap: 'wrap', + flexDirection: 'column', + padding: '1.5rem', + borderRadius: '0.4rem' +})); + +export const DesignHeading = styled('h1')(({ theme }) => ({ + textAlign: 'left', + margin: '0rem 0rem 2rem 0rem', + color: theme.palette.text.default, + textTransform: 'capitalize', + fontWeight: '300', + flex: '1' +})); + +export const ContentRow = styled('div')(() => ({ + padding: '0.5rem 0', + overflowWrap: 'anywhere' +})); + +export const ShowToggleBtn = styled('span')(({ theme }) => ({ + color: theme.palette.background.brand?.default, + cursor: 'pointer', + fontSize: '1rem', + fontWeight: 'normal', + marginLeft: '0.25rem' +})); + +export const AdditionalContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + textAlign: 'left', + justifyContent: 'center', + alignItems: 'center', + display: 'flex', + flexWrap: 'wrap', + flexDirection: 'column', + padding: '1.5rem', + paddingBottom: '2rem', + marginTop: '1.5rem', + borderRadius: '0.4rem' +})); + +export const DesignCardContainer = styled('div')(() => ({ + display: 'flex', + flexWrap: 'wrap', + flex: '0 0 75%', + gap: '2rem', + justifyContent: 'space-around', + height: 'fit-content' +})); + +export const CopyShareIconWrapper = styled(ContentHeading)(() => ({ + justifyContent: 'flex-end', + gap: '1rem', + width: 'fit-content' +})); + +export const VisibilityChip = styled('div')(() => ({ + borderRadius: '0.5rem', + border: '1px solid gray', + padding: '0.2rem 0.5rem', + textTransform: 'capitalize', + color: '#1a1a1acc', + width: 'fit-content' +})); + +export const RedirectLink = styled('a')(({ theme }) => ({ + color: theme.palette.background.brand?.default, + textDecoration: 'none', + cursor: 'pointer' +})); diff --git a/src/custom/index.tsx b/src/custom/index.tsx index a7505ea50..14e2b14ab 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -130,5 +130,6 @@ export type { UniversalFilterProps }; +export * from './CatalogDetail'; export * from './Dialog'; export * from './permissions'; From f0022cbff6adf0a31be7f52283584139d236d10b Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:54:41 +0530 Subject: [PATCH 04/15] refactor: Refactor CustomCatalog/CustomCard component Signed-off-by: Amit Amrutiya --- src/custom/CustomCatalog/CustomCard.tsx | 30 +++++++++++++++---------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/custom/CustomCatalog/CustomCard.tsx b/src/custom/CustomCatalog/CustomCard.tsx index 92517aa77..db62959b8 100644 --- a/src/custom/CustomCatalog/CustomCard.tsx +++ b/src/custom/CustomCatalog/CustomCard.tsx @@ -1,12 +1,11 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; -import { Avatar, styled } from '@mui/material'; import React, { useEffect, useState } from 'react'; -import { Grid } from '../../base'; +import { Avatar, Grid } from '../../base'; import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon } from '../../icons'; import VerificationClassIcon from '../../icons/ContentClassIcons/VerificationClassIcon'; import DeploymentsIcon from '../../icons/Deployments/DeploymentsIcon'; import { DownloadIcon } from '../../icons/Download'; -import { DARK_TEAL, useTheme } from '../../theme'; +import { DARK_TEAL, styled, useTheme } from '../../theme'; import { SNOW_WHITE } from '../../theme/colors/colors'; import { CustomTooltip } from '../CustomTooltip'; import { getVersion, handleImage } from './Helper'; @@ -42,6 +41,10 @@ export interface Pattern { id: string; user_id: string; pattern_file: string; + user: { + first_name: string; + last_name: string; + }; name: string; download_count: number; clone_count: number; @@ -61,18 +64,21 @@ export interface Pattern { compatibility?: string[]; published_version?: string; type?: string; + pattern_info?: string; + pattern_caveats?: string; }; visibility: string; updated_at: Date; + created_at: Date; } type CatalogCardProps = { pattern: Pattern; patternType: string; - cardHeight: string; - cardWidth: string; - cardStyles: React.CSSProperties; - avatarUrl: string; + cardHeight?: string; + cardWidth?: string; + cardStyles?: React.CSSProperties; + avatarUrl?: string; shouldFlip?: boolean; cardTechnologies?: boolean; isDetailed?: boolean; @@ -105,12 +111,12 @@ const ClassWrap = ({ catalogClassName }: { catalogClassName: string }) => { const CustomCatalogCard: React.FC = ({ pattern, patternType, - cardHeight, - cardWidth, + cardHeight = '18rem', + cardWidth = '15rem', cardStyles, - shouldFlip, - isDetailed, - cardTechnologies, + shouldFlip = true, + isDetailed = true, + cardTechnologies = true, avatarUrl, UserName, children, From c89b1275bbacdbbb2f82faf34442d01923f59ce9 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 18:55:37 +0530 Subject: [PATCH 05/15] feat: create leftpanel components of catalog detail Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/ActionButton.tsx | 116 ++++++++++++++++++ src/custom/CatalogDetail/CaveatsSection.tsx | 30 +++++ .../CatalogDetail/ChallengesSection.tsx | 71 +++++++++++ .../CatalogDetail/CollapsibleSection.tsx | 61 +++++++++ src/custom/CatalogDetail/ContentClassInfo.tsx | 48 ++++++++ src/custom/CatalogDetail/LearningSection.tsx | 70 +++++++++++ src/custom/CatalogDetail/LeftPanel.tsx | 101 +++++++++++++++ 7 files changed, 497 insertions(+) create mode 100644 src/custom/CatalogDetail/ActionButton.tsx create mode 100644 src/custom/CatalogDetail/CaveatsSection.tsx create mode 100644 src/custom/CatalogDetail/ChallengesSection.tsx create mode 100644 src/custom/CatalogDetail/CollapsibleSection.tsx create mode 100644 src/custom/CatalogDetail/ContentClassInfo.tsx create mode 100644 src/custom/CatalogDetail/LearningSection.tsx create mode 100644 src/custom/CatalogDetail/LeftPanel.tsx diff --git a/src/custom/CatalogDetail/ActionButton.tsx b/src/custom/CatalogDetail/ActionButton.tsx new file mode 100644 index 000000000..808835277 --- /dev/null +++ b/src/custom/CatalogDetail/ActionButton.tsx @@ -0,0 +1,116 @@ +import _ from 'lodash'; +import React from 'react'; +import { CircularProgress } from '../../base'; +import Download from '../../icons/Download/Download'; +import { charcoal } from '../../theme'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import CopyIcon from './Icons/CopyIcon'; +import KanvasIcon from './Icons/Kanvas'; +import { downloadFilter, downloadYaml, slugify } from './helper'; +import { ActionButton, LinkUrl, StyledActionWrapper } from './style'; +import { RESOURCE_TYPES } from './types'; + +interface ActionButtonsProps { + actionItems: boolean; + details: Pattern; + type: string; + cardId: string; + isCloneLoading: boolean; + handleClone: (name: string, id: string) => void; + mode: string; + isCloneDisabled: boolean; +} + +const ActionButtons: React.FC = ({ + actionItems, + details, + type, + cardId, + isCloneLoading, + handleClone, + mode, + isCloneDisabled +}) => { + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + const resourcePlaygroundType = Object.values({ + ..._.omit(RESOURCE_TYPES, ['FILTERS']), + CATALOG: 'catalog' + }).includes(cleanedType) + ? cleanedType + : 'design'; + return ( + + {actionItems && ( +
+ + cleanedType === RESOURCE_TYPES.FILTERS + ? downloadFilter(details.id, details.name) + : downloadYaml(details.pattern_file, details.name) + } + > + + Download + + + {cleanedType !== RESOURCE_TYPES.FILTERS && ( + handleClone(details?.name, details?.id)} + disabled={isCloneDisabled} + > + {isCloneLoading ? ( + + ) : ( + <> + + Clone + + )} + + )} +
+ )} + + + + Open in Playground + + +
+ ); +}; + +export default ActionButtons; diff --git a/src/custom/CatalogDetail/CaveatsSection.tsx b/src/custom/CatalogDetail/CaveatsSection.tsx new file mode 100644 index 000000000..71697a3d1 --- /dev/null +++ b/src/custom/CatalogDetail/CaveatsSection.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import { RenderMarkdown } from '../Markdown'; +import { ContentDetailsText } from '../Typography'; +import { CaveatsContainer, ContentHeading } from './style'; + +interface CaveatsSectionProps { + details: Pattern; +} + +const CaveatsSection: React.FC = ({ details }) => { + return ( + + +

CAVEATS AND CONSIDERATIONS

+
+ {details?.catalog_data?.pattern_caveats ? ( + + + + ) : ( + No caveats registered + )} +
+ ); +}; + +export default CaveatsSection; diff --git a/src/custom/CatalogDetail/ChallengesSection.tsx b/src/custom/CatalogDetail/ChallengesSection.tsx new file mode 100644 index 000000000..5110607b6 --- /dev/null +++ b/src/custom/CatalogDetail/ChallengesSection.tsx @@ -0,0 +1,71 @@ +import { useEffect, useState } from 'react'; +import { ListItemIcon } from '../../base'; +import { useTheme } from '../../theme'; +import CollapsibleSection from './CollapsibleSection'; +import ChallengesIcon from './Icons/ChallengesIcon'; +import { slugify } from './helper'; +import { LabelDiv } from './style'; +import { FilteredAcademyData } from './types'; + +interface ChallengesSectionProps { + filteredAcademyData: FilteredAcademyData; +} + +const ChallengesSection: React.FC = ({ filteredAcademyData }) => { + const theme = useTheme(); + const [openChallenges, setOpenChallenges] = useState(false); + const [autoUpdate, setAutoUpdate] = useState(true); + + useEffect(() => { + if (autoUpdate) { + setOpenChallenges((filteredAcademyData?.['challenges'] ?? []).length > 0); + } + }, [filteredAcademyData, autoUpdate]); + + const toggleOpenChallenges = () => { + setOpenChallenges((prev) => !prev); + setAutoUpdate(false); + }; + + const navigateToChallenge = (item: string) => { + window.location.href = `/academy/challenges/${slugify('' + item)}`; + }; + + const renderChallengeItem = (item: string, index: number) => ( + navigateToChallenge(item)}> + + + + {item} + + ); + + return ( + <> +
+ + + ); +}; + +export default ChallengesSection; diff --git a/src/custom/CatalogDetail/CollapsibleSection.tsx b/src/custom/CatalogDetail/CollapsibleSection.tsx new file mode 100644 index 000000000..24739f486 --- /dev/null +++ b/src/custom/CatalogDetail/CollapsibleSection.tsx @@ -0,0 +1,61 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import { Collapse, List, ListItemText } from '@mui/material'; +import { InfoTooltip } from '../CustomTooltip'; +import { SideContainer, SideTitleButton } from './style'; + +interface CollapsibleSectionProps { + title: string; + isOpen: boolean; + onToggle: () => void; + items: any[]; + renderItem: (item: any, index: number) => React.ReactNode; + emptyState: string; + tooltip: string; +} + +const CollapsibleSection: React.FC = ({ + title, + isOpen, + onToggle, + items, + renderItem, + emptyState, + tooltip +}) => { + return ( + + + + + {isOpen ? : } + + + {items && items.length > 0 ? ( + + {items?.map(renderItem)} + + ) : ( + + )} + + + ); +}; + +export default CollapsibleSection; diff --git a/src/custom/CatalogDetail/ContentClassInfo.tsx b/src/custom/CatalogDetail/ContentClassInfo.tsx new file mode 100644 index 000000000..5f2174993 --- /dev/null +++ b/src/custom/CatalogDetail/ContentClassInfo.tsx @@ -0,0 +1,48 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import { InfoTooltip } from '../CustomTooltip'; +import { ContentDetailsPoints, ContentDetailsText } from '../Typography'; +import { CONTENT_CLASS, formatToTitleCase } from './helper'; +import { Class } from './types'; + +interface ContentClassInfoProps { + contentClass: string; + classes: Class[]; +} + +const ClassIcon: React.FC<{ className: string }> = ({ className }) => { + const Icon = CONTENT_CLASS[className]?.icon; + return Icon ? : null; +}; + +const ContentClassInfo: React.FC = ({ contentClass, classes }) => { + const classDescription = (className: string): string | undefined => { + const classObj = classes && classes.find((classObj) => classObj.class === className); + return classObj?.description; + }; + + return ( +
+ + CLASS + + + + + {formatToTitleCase(contentClass)} + +
+ ); +}; + +export default ContentClassInfo; diff --git a/src/custom/CatalogDetail/LearningSection.tsx b/src/custom/CatalogDetail/LearningSection.tsx new file mode 100644 index 000000000..2763b2c37 --- /dev/null +++ b/src/custom/CatalogDetail/LearningSection.tsx @@ -0,0 +1,70 @@ +import React, { useEffect, useState } from 'react'; +import { ListItemIcon } from '../../base'; +import { useTheme } from '../../theme'; +import CollapsibleSection from './CollapsibleSection'; +import LearningIcon from './Icons/LearningIcon'; +import { slugify } from './helper'; +import { LabelDiv } from './style'; +import { FilteredAcademyData } from './types'; + +interface LearningSectionProps { + filteredAcademyData: FilteredAcademyData; +} + +const LearningSection: React.FC = ({ filteredAcademyData }) => { + const theme = useTheme(); + const [openLearning, setOpenLearning] = useState(false); + const [autoUpdate, setAutoUpdate] = useState(true); + + useEffect(() => { + if (autoUpdate) { + setOpenLearning(Boolean((filteredAcademyData?.['learning-path'] ?? []).length > 0)); + } + }, [filteredAcademyData, autoUpdate]); + + const toggleOpenLearning = (): void => { + setOpenLearning((prev) => !prev); + setAutoUpdate(false); + }; + + const navigateToLearningPath = (item: string): void => { + window.location.href = `/academy/learning-paths/${slugify('' + item)}`; + }; + + const renderLearningItem = (item: string, index: number) => ( + navigateToLearningPath(item)}> + + + + {item} + + ); + + return ( + <> +
+ + + ); +}; + +export default LearningSection; diff --git a/src/custom/CatalogDetail/LeftPanel.tsx b/src/custom/CatalogDetail/LeftPanel.tsx new file mode 100644 index 000000000..af1ac1602 --- /dev/null +++ b/src/custom/CatalogDetail/LeftPanel.tsx @@ -0,0 +1,101 @@ +import { useTheme } from '../../theme'; +import { CatalogCardDesignLogo, CustomCatalogCard } from '../CustomCatalog'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import ActionButtons from './ActionButton'; +import ChallengesSection from './ChallengesSection'; +import LearningSection from './LearningSection'; +import TechnologySection from './TechnologySection'; +import { FilteredAcademyData } from './types'; + +interface LeftPanelProps { + details: Pattern; + type: string; + cardId?: string; + actionItems?: boolean; + isCloneLoading: boolean; + handleClone: (name: string, id: string) => void; + showTechnologies?: boolean; + openTechnologies: boolean; + availableTechnologies: string[]; + handleOpenTechnologies: () => void; + mode: string; + filteredAcademyData: FilteredAcademyData; + isCloneDisabled: boolean; + technologySVGPath: string; + technologySVGSubpath: string; + fontFamily?: string; +} + +const LeftPanel: React.FC = ({ + details, + type, + cardId = details.id, + actionItems = true, + isCloneLoading, + handleClone, + showTechnologies = true, + openTechnologies, + availableTechnologies, + handleOpenTechnologies, + mode, + filteredAcademyData, + isCloneDisabled, + technologySVGPath, + technologySVGSubpath, + fontFamily +}) => { + const theme = useTheme(); + return ( +
+ + + + + {showTechnologies && ( + + )} + + +
+ ); +}; + +export default LeftPanel; From 76b032147ea21c826e0edb8d20e2a614c1fc073e Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 18:56:07 +0530 Subject: [PATCH 06/15] feat: create rightpanel components of catalog detail Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/MetricsDisplay.tsx | 38 +++++++ src/custom/CatalogDetail/OverviewSection.tsx | 105 ++++++++++++++++++ src/custom/CatalogDetail/PatternInfo.tsx | 45 ++++++++ src/custom/CatalogDetail/RelatedDesigns.tsx | 47 ++++++++ src/custom/CatalogDetail/RightPanel.tsx | 73 ++++++++++++ .../CatalogDetail/SocialSharePopper.tsx | 103 +++++++++++++++++ .../CatalogDetail/TechnologySection.tsx | 60 ++++++++++ src/custom/CatalogDetail/UserInfo.tsx | 42 +++++++ 8 files changed, 513 insertions(+) create mode 100644 src/custom/CatalogDetail/MetricsDisplay.tsx create mode 100644 src/custom/CatalogDetail/OverviewSection.tsx create mode 100644 src/custom/CatalogDetail/PatternInfo.tsx create mode 100644 src/custom/CatalogDetail/RelatedDesigns.tsx create mode 100644 src/custom/CatalogDetail/RightPanel.tsx create mode 100644 src/custom/CatalogDetail/SocialSharePopper.tsx create mode 100644 src/custom/CatalogDetail/TechnologySection.tsx create mode 100644 src/custom/CatalogDetail/UserInfo.tsx diff --git a/src/custom/CatalogDetail/MetricsDisplay.tsx b/src/custom/CatalogDetail/MetricsDisplay.tsx new file mode 100644 index 000000000..85cf7ec42 --- /dev/null +++ b/src/custom/CatalogDetail/MetricsDisplay.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Grid } from '../../base'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import { MetricsContainer, MetricsData, MetricsSection, MetricsType } from './style'; + +interface MetricItem { + label: string; + value: number; +} + +interface MetricsDisplayProps { + details: Pattern; +} + +const MetricsDisplay: React.FC = ({ details }) => { + const metrics: MetricItem[] = [ + { label: 'Opens', value: details.view_count }, + { label: 'Downloads', value: details.download_count }, + { label: 'Deploys', value: details.deployment_count }, + { label: 'Clones', value: details.clone_count }, + { label: 'Shares', value: details.share_count } + ]; + + return ( + + + {metrics.map((metric) => ( + + {metric.value} + {metric.label} + + ))} + + + ); +}; + +export default MetricsDisplay; diff --git a/src/custom/CatalogDetail/OverviewSection.tsx b/src/custom/CatalogDetail/OverviewSection.tsx new file mode 100644 index 000000000..756d2f7f2 --- /dev/null +++ b/src/custom/CatalogDetail/OverviewSection.tsx @@ -0,0 +1,105 @@ +import { Grid } from '@mui/material'; +import React from 'react'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import ContentClassInfo from './ContentClassInfo'; +import MetricsDisplay from './MetricsDisplay'; +import PatternInfo from './PatternInfo'; +import SocialSharePopper from './SocialSharePopper'; +import UserInfo from './UserInfo'; +import { ContentRow, DesignHeading, OverviewContainer } from './style'; +import { Class } from './types'; + +interface OverviewSectionProps { + details: Pattern; + type: string; + cardId: string; + handleClick: (event: React.MouseEvent) => void; + title: string; + id: string; + anchorEl: HTMLElement | null; + handleClose: () => void; + getUrl: (type: string, id: string) => string; + showContentDetails: boolean; + ViewsComponent?: React.ReactNode; + showVersion: boolean; + classes: Class[]; + handleCopyUrl: (type: string, name: string, id: string) => void; +} + +const OverviewSection: React.FC = ({ + details, + type, + cardId, + handleClick, + title, + id, + anchorEl, + handleClose, + getUrl, + showContentDetails, + ViewsComponent, + showVersion, + classes, + handleCopyUrl +}) => { + return ( + +
+ {details?.name} + +
+ + + + + {details?.catalog_data?.content_class && ( + + + + )} + + + + + + {showContentDetails ? ( + +

WHAT DOES THIS DESIGN DO?

+ {details?.catalog_data?.pattern_info ? ( + + ) : ( +
No description available
+ )} +
+ ) : ( + ViewsComponent + )} +
+ {!(type === 'view' || type === 'filter') && } +
+
+ ); +}; + +export default OverviewSection; diff --git a/src/custom/CatalogDetail/PatternInfo.tsx b/src/custom/CatalogDetail/PatternInfo.tsx new file mode 100644 index 000000000..6371ddcd7 --- /dev/null +++ b/src/custom/CatalogDetail/PatternInfo.tsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react'; +import { RenderMarkdown } from '../Markdown'; +import { ShowToggleBtn } from './style'; + +interface PatternInfoProps { + text: string; + redirect?: boolean; + id?: string; +} + +const PatternInfo: React.FC = ({ text, redirect, id }) => { + const [isExpanded, setIsExpanded] = useState(false); + + const toggleExpand = () => { + setIsExpanded(!isExpanded); + }; + + const handleRedirect = () => { + if (id) { + window.location.href = `/catalog/content/design/${id}`; + } + }; + + return ( +
+ {isExpanded ? ( +
+ + show less +
+ ) : ( +
+ + {text.length > (redirect ? 400 : 500) && ( + + ...show more + + )} +
+ )} +
+ ); +}; + +export default PatternInfo; diff --git a/src/custom/CatalogDetail/RelatedDesigns.tsx b/src/custom/CatalogDetail/RelatedDesigns.tsx new file mode 100644 index 000000000..5b000b86f --- /dev/null +++ b/src/custom/CatalogDetail/RelatedDesigns.tsx @@ -0,0 +1,47 @@ +import { CatalogCardDesignLogo } from '../CustomCatalog'; +import CustomCatalogCard, { Pattern } from '../CustomCatalog/CustomCard'; +import { formatToTitleCase } from './helper'; +import { AdditionalContainer, ContentHeading, DesignCardContainer } from './style'; + +export interface PatternsPerUser { + patterns: Pattern[]; +} + +interface RelatedDesignsProps { + details: Pattern; + type: string; + patternsPerUser: PatternsPerUser; +} + +const RelatedDesigns: React.FC = ({ details, type, patternsPerUser }) => { + const filteredPatternsPerUser = patternsPerUser?.patterns?.filter( + (pattern) => pattern.id !== details.id + ); + + if (!filteredPatternsPerUser?.length) return null; + + return ( + + +

+ Other published design by {formatToTitleCase(details.user.first_name)} +

+
+ + {filteredPatternsPerUser.map((pattern, index) => ( + + + + ))} + +
+ ); +}; + +export default RelatedDesigns; diff --git a/src/custom/CatalogDetail/RightPanel.tsx b/src/custom/CatalogDetail/RightPanel.tsx new file mode 100644 index 000000000..4d3c0609d --- /dev/null +++ b/src/custom/CatalogDetail/RightPanel.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import CaveatsSection from './CaveatsSection'; +import OverviewSection from './OverviewSection'; +import RelatedDesigns, { PatternsPerUser } from './RelatedDesigns'; +import { Class } from './types'; + +interface RightPanelProps { + details: Pattern; + type: string; + cardId: string; + handleClick: (event: React.MouseEvent) => void; + title: string; + id?: string; + anchorEl: HTMLElement | null; + handleClose: () => void; + getUrl: (type: string, id: string) => string; + showContentDetails: boolean; + ViewsComponent?: React.ReactNode; + showVersion: boolean; + showCaveats: boolean; + classes: Class[]; + patternsPerUser: PatternsPerUser; + handleCopyUrl: (type: string, name: string, id: string) => void; + fontFamily?: string; +} + +const RightPanel: React.FC = ({ + details, + type, + cardId, + handleClick, + title, + id = '', + anchorEl, + handleClose, + getUrl, + showContentDetails, + ViewsComponent, + showVersion, + showCaveats, + classes, + patternsPerUser, + handleCopyUrl, + fontFamily +}) => { + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + + return ( +
+ + {showCaveats && } + +
+ ); +}; + +export default RightPanel; diff --git a/src/custom/CatalogDetail/SocialSharePopper.tsx b/src/custom/CatalogDetail/SocialSharePopper.tsx new file mode 100644 index 000000000..ae3bf24be --- /dev/null +++ b/src/custom/CatalogDetail/SocialSharePopper.tsx @@ -0,0 +1,103 @@ +import { + ClickAwayListener, + Fade, + IconButton, + Paper, + Popper, + Tooltip, + useTheme +} from '@mui/material'; +import React from 'react'; +import { FacebookShareButton, LinkedinShareButton, TwitterShareButton } from 'react-share'; +import { ShareIcon } from '../../icons'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import ChainIcon from './Icons/ChainIcon'; +import { FacebookIcon, LinkedinIcon, TwitterIcon } from './Icons/SocialMediaIcon'; +import { CopyShareIconWrapper, VisibilityChip } from './style'; + +interface SocialSharePopperProps { + details: Pattern; + type: string; + cardId: string; + handleClick: (event: React.MouseEvent) => void; + title: string; + id: string; + anchorEl: HTMLElement | null; + handleClose: () => void; + getUrl: (type: string, id: string) => string; + handleCopyUrl: (type: string, name: string, id: string) => void; +} + +const SocialSharePopper: React.FC = ({ + details, + type, + cardId, + handleClick, + title, + id, + anchorEl, + handleClose, + getUrl, + handleCopyUrl +}) => { + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + const theme = useTheme(); + return ( + + + {details?.visibility} + + {details?.visibility !== 'private' && ( + + handleCopyUrl(cleanedType, details?.name, details?.id)} + > + + + + )} + {(details?.visibility === 'published' || details?.visibility === 'public') && ( + <> + + + + + + + {({ TransitionProps }) => ( + + + + + + + + + + + + + + + + )} + + + )} + + ); +}; + +export default SocialSharePopper; diff --git a/src/custom/CatalogDetail/TechnologySection.tsx b/src/custom/CatalogDetail/TechnologySection.tsx new file mode 100644 index 000000000..2bddd5961 --- /dev/null +++ b/src/custom/CatalogDetail/TechnologySection.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { ListItemIcon } from '../../base'; +import { useTheme } from '../../theme'; +import CollapsibleSection from './CollapsibleSection'; +import { LabelDiv } from './style'; + +interface TechnologySectionProps { + availableTechnologies: string[]; + openTechnologies: boolean; + handleOpenTechnologies: () => void; + technologySVGPath: string; + technologySVGSubpath: string; +} + +const TechnologySection: React.FC = ({ + availableTechnologies, + openTechnologies, + handleOpenTechnologies, + technologySVGPath, + technologySVGSubpath +}) => { + const theme = useTheme(); + + const renderTechnologyItem = (item: string, index: number) => { + const svg_path = `${technologySVGPath}/${item.toLowerCase()}/${technologySVGSubpath}/${item.toLowerCase()}-color.svg`; + return ( + + + technology icon + + {item} + + ); + }; + + return ( + <> +
+ + + ); +}; + +export default TechnologySection; diff --git a/src/custom/CatalogDetail/UserInfo.tsx b/src/custom/CatalogDetail/UserInfo.tsx new file mode 100644 index 000000000..6a2222491 --- /dev/null +++ b/src/custom/CatalogDetail/UserInfo.tsx @@ -0,0 +1,42 @@ +import { Pattern } from '../CustomCatalog/CustomCard'; +import { getVersion } from '../CustomCatalog/Helper'; +import { formatDate } from './helper'; +import { ContentDetailsPoints, ContentDetailsText, ContentRow, RedirectLink } from './style'; + +interface UserInfoProps { + details: Pattern; + showVersion?: boolean; +} + +const UserInfo: React.FC = ({ details, showVersion = true }) => { + return ( + <> + + CREATED BY + + + + {details.user.first_name} {details?.user?.last_name} + + + + + + CREATED AT + {formatDate(details?.created_at)} + + + UPDATED AT + {formatDate(details?.updated_at)} + + {showVersion && ( + + VERSION + {getVersion(details)} + + )} + + ); +}; + +export default UserInfo; From 17abeaee9c21dd1209f29b07fc155e65f54bb766 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 19:18:25 +0530 Subject: [PATCH 07/15] feat: add new icons for detail component Signed-off-by: Amit Amrutiya --- src/icons/Chain/ChainIcon.tsx | 24 +++++++++++ src/icons/Chain/index.ts | 1 + src/icons/Challenges/ChallengesIcon.tsx | 56 +++++++++++++++++++++++++ src/icons/Challenges/index.ts | 1 + src/icons/Copy/CopyIcon.tsx | 26 ++++++++++++ src/icons/Copy/index.ts | 1 + src/icons/Kanvas/KanvasIcon.tsx | 43 +++++++++++++++++++ src/icons/Kanvas/index.ts | 1 + src/icons/Learning/LearningIcon.tsx | 43 +++++++++++++++++++ src/icons/Learning/index.ts | 1 + src/icons/Share/ShareLineIcon.tsx | 32 ++++++++++++++ src/icons/Share/index.tsx | 3 +- src/icons/SocialMedial/FacebookIcon.tsx | 51 ++++++++++++++++++++++ src/icons/SocialMedial/LinkedinIcon.tsx | 51 ++++++++++++++++++++++ src/icons/SocialMedial/TwitterIcon.tsx | 51 ++++++++++++++++++++++ src/icons/SocialMedial/index.ts | 5 +++ src/icons/SocialMedial/types.ts | 6 +++ src/icons/index.ts | 5 +++ 18 files changed, 400 insertions(+), 1 deletion(-) create mode 100644 src/icons/Chain/ChainIcon.tsx create mode 100644 src/icons/Chain/index.ts create mode 100644 src/icons/Challenges/ChallengesIcon.tsx create mode 100644 src/icons/Challenges/index.ts create mode 100644 src/icons/Copy/CopyIcon.tsx create mode 100644 src/icons/Kanvas/KanvasIcon.tsx create mode 100644 src/icons/Kanvas/index.ts create mode 100644 src/icons/Learning/LearningIcon.tsx create mode 100644 src/icons/Learning/index.ts create mode 100644 src/icons/Share/ShareLineIcon.tsx create mode 100644 src/icons/SocialMedial/FacebookIcon.tsx create mode 100644 src/icons/SocialMedial/LinkedinIcon.tsx create mode 100644 src/icons/SocialMedial/TwitterIcon.tsx create mode 100644 src/icons/SocialMedial/index.ts create mode 100644 src/icons/SocialMedial/types.ts diff --git a/src/icons/Chain/ChainIcon.tsx b/src/icons/Chain/ChainIcon.tsx new file mode 100644 index 000000000..727bfa386 --- /dev/null +++ b/src/icons/Chain/ChainIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +interface ChainIconProps { + width: string; + height: string; + fill?: string; + style?: React.CSSProperties; + secondaryFill?: string; +} + +const ChainIcon: React.FC = ({ width, height, style, fill = '#3C494F' }) => ( + + + +); + +export default ChainIcon; diff --git a/src/icons/Chain/index.ts b/src/icons/Chain/index.ts new file mode 100644 index 000000000..043710db5 --- /dev/null +++ b/src/icons/Chain/index.ts @@ -0,0 +1 @@ +export { default as ChainIcon } from './ChainIcon'; diff --git a/src/icons/Challenges/ChallengesIcon.tsx b/src/icons/Challenges/ChallengesIcon.tsx new file mode 100644 index 000000000..94b9b7b7a --- /dev/null +++ b/src/icons/Challenges/ChallengesIcon.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +interface ChallengesIconProps { + width?: string; + height?: string; + primaryFill?: string; + brandFill?: string; + secondaryFill?: string; + style?: React.CSSProperties; +} + +const ChallengesIcon: React.FC = ({ + width = '32px', + height = '32px', + primaryFill = '#B1B9BC', + brandFill = '#00B39F', + secondaryFill = '#51636B', + style = {} +}) => ( + + + + + + + + + + +); + +export default ChallengesIcon; diff --git a/src/icons/Challenges/index.ts b/src/icons/Challenges/index.ts new file mode 100644 index 000000000..e9cf9c6d5 --- /dev/null +++ b/src/icons/Challenges/index.ts @@ -0,0 +1 @@ +export { default as ChallengesIcon } from './ChallengesIcon'; diff --git a/src/icons/Copy/CopyIcon.tsx b/src/icons/Copy/CopyIcon.tsx new file mode 100644 index 000000000..e5edf8895 --- /dev/null +++ b/src/icons/Copy/CopyIcon.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +interface CopyIconProps { + width: number; + height: number; + fill?: string; + style?: React.CSSProperties; + secondaryFill?: string; +} + +const CopyIcon: React.FC = ({ width, height, fill = 'white', style }) => ( + + + + + +); + +export default CopyIcon; diff --git a/src/icons/Copy/index.ts b/src/icons/Copy/index.ts index 48fc57203..cd7aaba8a 100644 --- a/src/icons/Copy/index.ts +++ b/src/icons/Copy/index.ts @@ -1 +1,2 @@ +export { default as CopyIcon } from './CopyIcon'; export { default as CopyLinkIcon } from './CopyLinkIcon'; diff --git a/src/icons/Kanvas/KanvasIcon.tsx b/src/icons/Kanvas/KanvasIcon.tsx new file mode 100644 index 000000000..affe38816 --- /dev/null +++ b/src/icons/Kanvas/KanvasIcon.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +interface KanvasIconProps { + width: number; + height: number; + fill?: string; + style?: React.CSSProperties; + primaryFill?: string; + secondaryFill?: string; +} + +const KanvasIcon: React.FC = ({ + width, + height, + fill, + style, + primaryFill = 'white' +}) => ( + + + + + + + + + + + + + + +); + +export default KanvasIcon; diff --git a/src/icons/Kanvas/index.ts b/src/icons/Kanvas/index.ts new file mode 100644 index 000000000..3d2dcdd5c --- /dev/null +++ b/src/icons/Kanvas/index.ts @@ -0,0 +1 @@ +export { default as KanvasIcon } from './KanvasIcon'; diff --git a/src/icons/Learning/LearningIcon.tsx b/src/icons/Learning/LearningIcon.tsx new file mode 100644 index 000000000..cf485d448 --- /dev/null +++ b/src/icons/Learning/LearningIcon.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +interface LearningIconProps { + width?: string; + height?: string; + primaryFill?: string; + secondaryFill?: string; + style?: React.CSSProperties; +} + +const LearningIcon: React.FC = ({ + width = '32px', + height = '32px', + primaryFill = '#FDFDFD', + secondaryFill = '#FDFDFD', + style = {} +}) => ( + + + + +); + +export default LearningIcon; diff --git a/src/icons/Learning/index.ts b/src/icons/Learning/index.ts new file mode 100644 index 000000000..4849b25e4 --- /dev/null +++ b/src/icons/Learning/index.ts @@ -0,0 +1 @@ +export { default as LearningIcon } from './LearningIcon'; diff --git a/src/icons/Share/ShareLineIcon.tsx b/src/icons/Share/ShareLineIcon.tsx new file mode 100644 index 000000000..6a4c6fd3a --- /dev/null +++ b/src/icons/Share/ShareLineIcon.tsx @@ -0,0 +1,32 @@ +import React from 'react'; + +interface ShareLineIconProps { + width: string; + height: string; + fill?: string; + style?: React.CSSProperties; + secondaryFill?: string; +} + +const ShareLineIcon: React.FC = ({ + width, + height, + style, + fill = '#3C494F' +}) => ( + + + +); + +export default ShareLineIcon; diff --git a/src/icons/Share/index.tsx b/src/icons/Share/index.tsx index 182307123..5abf944db 100644 --- a/src/icons/Share/index.tsx +++ b/src/icons/Share/index.tsx @@ -1,2 +1,3 @@ import ShareIcon from './ShareIcon'; -export { ShareIcon }; +import ShareLineIcon from './ShareLineIcon'; +export { ShareIcon, ShareLineIcon }; diff --git a/src/icons/SocialMedial/FacebookIcon.tsx b/src/icons/SocialMedial/FacebookIcon.tsx new file mode 100644 index 000000000..0fcf1ea65 --- /dev/null +++ b/src/icons/SocialMedial/FacebookIcon.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { IconProps } from './types'; + +const FacebookIcon: React.FC = ({ width = 40, height = 40 }) => ( + + + + + + + + + + + + + + + + + +); + +export default FacebookIcon; diff --git a/src/icons/SocialMedial/LinkedinIcon.tsx b/src/icons/SocialMedial/LinkedinIcon.tsx new file mode 100644 index 000000000..5ca0d4948 --- /dev/null +++ b/src/icons/SocialMedial/LinkedinIcon.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { IconProps } from './types'; + +const LinkedinIcon: React.FC = ({ width = 40, height = 40 }) => ( + + + + + + + + + + + + + + + + + +); + +export default LinkedinIcon; diff --git a/src/icons/SocialMedial/TwitterIcon.tsx b/src/icons/SocialMedial/TwitterIcon.tsx new file mode 100644 index 000000000..df8172d42 --- /dev/null +++ b/src/icons/SocialMedial/TwitterIcon.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { IconProps } from './types'; + +const TwitterIcon: React.FC = ({ width = 40, height = 40 }) => ( + + + + + + + + + + + + + + + + + +); + +export default TwitterIcon; diff --git a/src/icons/SocialMedial/index.ts b/src/icons/SocialMedial/index.ts new file mode 100644 index 000000000..1b3be9b14 --- /dev/null +++ b/src/icons/SocialMedial/index.ts @@ -0,0 +1,5 @@ +import FacebookIcon from './FacebookIcon'; +import LinkedinIcon from './LinkedinIcon'; +import TwitterIcon from './TwitterIcon'; + +export { FacebookIcon, LinkedinIcon, TwitterIcon }; diff --git a/src/icons/SocialMedial/types.ts b/src/icons/SocialMedial/types.ts new file mode 100644 index 000000000..f1505e285 --- /dev/null +++ b/src/icons/SocialMedial/types.ts @@ -0,0 +1,6 @@ +export interface IconProps { + width?: number; + height?: number; + fill?: string; + style?: React.CSSProperties; +} diff --git a/src/icons/index.ts b/src/icons/index.ts index c7bf87e66..e280c8992 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -40,6 +40,8 @@ export * from './Mesh'; // export { default as ModifiedApplicationFileIcon } from "./ModifiedApplicationFileIcon"; // export { default as OriginalApplicationFileIcon } from "./OriginalApplicationFileIcon"; export * from './Calender'; +export * from './Chain'; +export * from './Challenges'; export * from './ChevronLeft'; export * from './ContentClassIcons'; export * from './Deployments'; @@ -54,7 +56,9 @@ export * from './Feedback'; export * from './HelpIcon'; export * from './Idea'; export * from './InfoOutlined'; +export * from './Kanvas'; export * from './Kubernetes'; +export * from './Learning'; export * from './LeftAngledArrow'; export * from './LeftArrow'; export * from './Menu'; @@ -79,6 +83,7 @@ export * from './Screenshot'; export * from './Search'; export * from './Settings'; export * from './Share'; +export * from './SocialMedial'; export * from './Star'; export * from './Success'; export * from './TerminalIcon'; From 4ff52d6fa41fb5cb40e6f75e64c2cb3ad514ae19 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 19:19:01 +0530 Subject: [PATCH 08/15] chore: update import path and use sistent component Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/ActionButton.tsx | 3 +-- src/custom/CatalogDetail/ChallengesSection.tsx | 2 +- src/custom/CatalogDetail/CollapsibleSection.tsx | 2 +- src/custom/CatalogDetail/ContentClassInfo.tsx | 2 +- src/custom/CatalogDetail/LearningSection.tsx | 2 +- src/custom/CatalogDetail/OverviewSection.tsx | 2 +- src/custom/CatalogDetail/SocialSharePopper.tsx | 16 ++++------------ 7 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/custom/CatalogDetail/ActionButton.tsx b/src/custom/CatalogDetail/ActionButton.tsx index 808835277..e7a9806d7 100644 --- a/src/custom/CatalogDetail/ActionButton.tsx +++ b/src/custom/CatalogDetail/ActionButton.tsx @@ -1,11 +1,10 @@ import _ from 'lodash'; import React from 'react'; import { CircularProgress } from '../../base'; +import { CopyIcon, KanvasIcon } from '../../icons'; import Download from '../../icons/Download/Download'; import { charcoal } from '../../theme'; import { Pattern } from '../CustomCatalog/CustomCard'; -import CopyIcon from './Icons/CopyIcon'; -import KanvasIcon from './Icons/Kanvas'; import { downloadFilter, downloadYaml, slugify } from './helper'; import { ActionButton, LinkUrl, StyledActionWrapper } from './style'; import { RESOURCE_TYPES } from './types'; diff --git a/src/custom/CatalogDetail/ChallengesSection.tsx b/src/custom/CatalogDetail/ChallengesSection.tsx index 5110607b6..7bec37c9f 100644 --- a/src/custom/CatalogDetail/ChallengesSection.tsx +++ b/src/custom/CatalogDetail/ChallengesSection.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from 'react'; import { ListItemIcon } from '../../base'; +import { ChallengesIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; -import ChallengesIcon from './Icons/ChallengesIcon'; import { slugify } from './helper'; import { LabelDiv } from './style'; import { FilteredAcademyData } from './types'; diff --git a/src/custom/CatalogDetail/CollapsibleSection.tsx b/src/custom/CatalogDetail/CollapsibleSection.tsx index 24739f486..49c417947 100644 --- a/src/custom/CatalogDetail/CollapsibleSection.tsx +++ b/src/custom/CatalogDetail/CollapsibleSection.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import { Collapse, List, ListItemText } from '@mui/material'; +import { Collapse, List, ListItemText } from '../../base'; import { InfoTooltip } from '../CustomTooltip'; import { SideContainer, SideTitleButton } from './style'; diff --git a/src/custom/CatalogDetail/ContentClassInfo.tsx b/src/custom/CatalogDetail/ContentClassInfo.tsx index 5f2174993..5a9b871e2 100644 --- a/src/custom/CatalogDetail/ContentClassInfo.tsx +++ b/src/custom/CatalogDetail/ContentClassInfo.tsx @@ -1,5 +1,5 @@ -import { Box } from '@mui/material'; import React from 'react'; +import { Box } from '../../base'; import { InfoTooltip } from '../CustomTooltip'; import { ContentDetailsPoints, ContentDetailsText } from '../Typography'; import { CONTENT_CLASS, formatToTitleCase } from './helper'; diff --git a/src/custom/CatalogDetail/LearningSection.tsx b/src/custom/CatalogDetail/LearningSection.tsx index 2763b2c37..ffc003c72 100644 --- a/src/custom/CatalogDetail/LearningSection.tsx +++ b/src/custom/CatalogDetail/LearningSection.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from 'react'; import { ListItemIcon } from '../../base'; +import { LearningIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; -import LearningIcon from './Icons/LearningIcon'; import { slugify } from './helper'; import { LabelDiv } from './style'; import { FilteredAcademyData } from './types'; diff --git a/src/custom/CatalogDetail/OverviewSection.tsx b/src/custom/CatalogDetail/OverviewSection.tsx index 756d2f7f2..a933226f7 100644 --- a/src/custom/CatalogDetail/OverviewSection.tsx +++ b/src/custom/CatalogDetail/OverviewSection.tsx @@ -1,5 +1,5 @@ -import { Grid } from '@mui/material'; import React from 'react'; +import { Grid } from '../../base'; import { Pattern } from '../CustomCatalog/CustomCard'; import ContentClassInfo from './ContentClassInfo'; import MetricsDisplay from './MetricsDisplay'; diff --git a/src/custom/CatalogDetail/SocialSharePopper.tsx b/src/custom/CatalogDetail/SocialSharePopper.tsx index ae3bf24be..ad6ae2cf3 100644 --- a/src/custom/CatalogDetail/SocialSharePopper.tsx +++ b/src/custom/CatalogDetail/SocialSharePopper.tsx @@ -1,18 +1,10 @@ -import { - ClickAwayListener, - Fade, - IconButton, - Paper, - Popper, - Tooltip, - useTheme -} from '@mui/material'; +import { Fade } from '@mui/material'; import React from 'react'; import { FacebookShareButton, LinkedinShareButton, TwitterShareButton } from 'react-share'; -import { ShareIcon } from '../../icons'; +import { ClickAwayListener, IconButton, Paper, Popper, Tooltip } from '../../base'; +import { ChainIcon, FacebookIcon, LinkedinIcon, ShareIcon, TwitterIcon } from '../../icons'; +import { useTheme } from '../../theme'; import { Pattern } from '../CustomCatalog/CustomCard'; -import ChainIcon from './Icons/ChainIcon'; -import { FacebookIcon, LinkedinIcon, TwitterIcon } from './Icons/SocialMediaIcon'; import { CopyShareIconWrapper, VisibilityChip } from './style'; interface SocialSharePopperProps { From 63b3a06875c88d13f46cda5f3df8fef0a743bcb2 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:51:17 +0530 Subject: [PATCH 09/15] chore: udpate font-family Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/CaveatsSection.tsx | 2 +- src/custom/CatalogDetail/ContentClassInfo.tsx | 45 ++++++++++++++----- src/custom/CatalogDetail/style.tsx | 11 +++-- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/custom/CatalogDetail/CaveatsSection.tsx b/src/custom/CatalogDetail/CaveatsSection.tsx index 71697a3d1..489be4133 100644 --- a/src/custom/CatalogDetail/CaveatsSection.tsx +++ b/src/custom/CatalogDetail/CaveatsSection.tsx @@ -15,7 +15,7 @@ const CaveatsSection: React.FC = ({ details }) => {

CAVEATS AND CONSIDERATIONS

{details?.catalog_data?.pattern_caveats ? ( - + diff --git a/src/custom/CatalogDetail/ContentClassInfo.tsx b/src/custom/CatalogDetail/ContentClassInfo.tsx index 5a9b871e2..effd24378 100644 --- a/src/custom/CatalogDetail/ContentClassInfo.tsx +++ b/src/custom/CatalogDetail/ContentClassInfo.tsx @@ -1,33 +1,55 @@ import React from 'react'; import { Box } from '../../base'; +import { CommunityClassIcon, OfficialClassIcon, VerificationClassIcon } from '../../icons'; +import { KEPPEL, useTheme } from '../../theme'; import { InfoTooltip } from '../CustomTooltip'; import { ContentDetailsPoints, ContentDetailsText } from '../Typography'; -import { CONTENT_CLASS, formatToTitleCase } from './helper'; -import { Class } from './types'; +import { formatToTitleCase } from './helper'; +import { Class, ContentClassType } from './types'; interface ContentClassInfoProps { contentClass: string; classes: Class[]; } -const ClassIcon: React.FC<{ className: string }> = ({ className }) => { - const Icon = CONTENT_CLASS[className]?.icon; - return Icon ? : null; -}; - const ContentClassInfo: React.FC = ({ contentClass, classes }) => { - const classDescription = (className: string): string | undefined => { + const _classDescription = (className: string): string | undefined => { const classObj = classes && classes.find((classObj) => classObj.class === className); return classObj?.description; }; + const theme = useTheme(); + + const CONTENT_CLASS: ContentClassType = { + community: { + icon: CommunityClassIcon, + color: theme.palette.icon.secondary + }, + official: { + icon: OfficialClassIcon, + color: '#EBC017' + }, + verified: { + icon: VerificationClassIcon, + color: theme.palette.primary.brand?.default || KEPPEL + } + } as const; + + const ClassIcon: React.FC<{ className: string }> = ({ className }) => { + const Icon = CONTENT_CLASS[className]?.icon; + const fill = CONTENT_CLASS[className]?.color; + return Icon ? : null; + }; + return (
- CLASS + + CLASS + @@ -35,7 +57,8 @@ const ContentClassInfo: React.FC = ({ contentClass, class style={{ display: 'flex', alignItems: 'center', - gap: '0.4rem' + gap: '0.4rem', + fontFamily: 'inherit' }} > diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx index 19e91d765..f35b8140a 100644 --- a/src/custom/CatalogDetail/style.tsx +++ b/src/custom/CatalogDetail/style.tsx @@ -1,4 +1,4 @@ -import { ListItemButton, Paper, Typography } from '../../base'; +import { Link, ListItemButton, Paper, Typography } from '../../base'; import { styled } from '../../theme'; import { Theme } from './types'; @@ -40,6 +40,7 @@ export const ActionButton = styled('div')(({ disabled = false })); export const ContentDetailsText = styled(Typography)(({ theme }) => ({ + fontFamily: 'inherit', fontSize: '1rem', color: theme.palette.text.default, ['@media (min-width:1200px)']: { @@ -122,7 +123,8 @@ export const ContentDetailsPoints = styled(Typography)(() => ({ display: 'flex', flexDirection: 'row', alignItems: 'center', - gap: '1rem' + gap: '1rem', + fontFamily: 'inherit' })); export const MetricsSection = styled('div')(() => ({ @@ -194,7 +196,8 @@ export const DesignHeading = styled('h1')(({ theme }) => ({ export const ContentRow = styled('div')(() => ({ padding: '0.5rem 0', - overflowWrap: 'anywhere' + overflowWrap: 'anywhere', + fontFamily: 'inherit' })); export const ShowToggleBtn = styled('span')(({ theme }) => ({ @@ -245,7 +248,7 @@ export const VisibilityChip = styled('div')(() => ({ width: 'fit-content' })); -export const RedirectLink = styled('a')(({ theme }) => ({ +export const RedirectLink = styled(Link)(({ theme }) => ({ color: theme.palette.background.brand?.default, textDecoration: 'none', cursor: 'pointer' From 166bc6ec3eeca6343395cdd0b5f0d7e394c18fc8 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:52:00 +0530 Subject: [PATCH 10/15] feat: remove any and add types Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/helper.ts | 14 -------------- src/custom/CatalogDetail/types.ts | 9 +++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/custom/CatalogDetail/helper.ts b/src/custom/CatalogDetail/helper.ts index a46311c41..2d6601f77 100644 --- a/src/custom/CatalogDetail/helper.ts +++ b/src/custom/CatalogDetail/helper.ts @@ -1,6 +1,4 @@ import jsyaml from 'js-yaml'; -import { CommunityClassIcon, OfficialClassIcon, VerificationClassIcon } from '../../icons'; -import { ContentClassType } from './types'; export const downloadYaml = (filteredData: string, itemName: string): void => { const yamlData = Array.isArray(filteredData) @@ -49,18 +47,6 @@ export const downloadFilter = (id: string, name: string): void => { linkElement.remove(); }; -export const CONTENT_CLASS: ContentClassType = { - community: { - icon: CommunityClassIcon - }, - official: { - icon: OfficialClassIcon - }, - verified: { - icon: VerificationClassIcon - } -}; - export const formatToTitleCase = (value: string): string => { if (typeof value === 'string') { return value.substring(0, 1).toUpperCase().concat('', value.substring(1).toLowerCase()); diff --git a/src/custom/CatalogDetail/types.ts b/src/custom/CatalogDetail/types.ts index 40d8b2d38..1cd2adc78 100644 --- a/src/custom/CatalogDetail/types.ts +++ b/src/custom/CatalogDetail/types.ts @@ -40,11 +40,20 @@ export const RESOURCE_TYPES = { export type ContentClassType = { community: { icon: React.ComponentType; + color: string; }; official: { icon: React.ComponentType; + color: string; }; verified: { icon: React.ComponentType; + color: string; }; }; + +export type UserProfile = { + first_name: string; + last_name: string; + avatar_url: string; +}; From 88cf288b62121af0204d2f43a2c217cc116743c4 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:52:54 +0530 Subject: [PATCH 11/15] chore: some of the props and update funtions Signed-off-by: Amit Amrutiya --- .../CatalogDetail/ChallengesSection.tsx | 33 +++++++++-------- src/custom/CatalogDetail/LearningSection.tsx | 31 ++++++++-------- src/custom/CatalogDetail/OverviewSection.tsx | 26 ++++++-------- src/custom/CatalogDetail/RelatedDesigns.tsx | 28 ++++++++++++--- src/custom/CatalogDetail/RightPanel.tsx | 36 ++++++++++--------- 5 files changed, 89 insertions(+), 65 deletions(-) diff --git a/src/custom/CatalogDetail/ChallengesSection.tsx b/src/custom/CatalogDetail/ChallengesSection.tsx index 7bec37c9f..77028a2f0 100644 --- a/src/custom/CatalogDetail/ChallengesSection.tsx +++ b/src/custom/CatalogDetail/ChallengesSection.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { ListItemIcon } from '../../base'; +import { Link, ListItemIcon } from '../../base'; import { ChallengesIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; @@ -27,21 +27,24 @@ const ChallengesSection: React.FC = ({ filteredAcademyDa setAutoUpdate(false); }; - const navigateToChallenge = (item: string) => { - window.location.href = `/academy/challenges/${slugify('' + item)}`; - }; - const renderChallengeItem = (item: string, index: number) => ( - navigateToChallenge(item)}> - - - - {item} - + + + + + + {item} + + ); return ( diff --git a/src/custom/CatalogDetail/LearningSection.tsx b/src/custom/CatalogDetail/LearningSection.tsx index ffc003c72..d6e308075 100644 --- a/src/custom/CatalogDetail/LearningSection.tsx +++ b/src/custom/CatalogDetail/LearningSection.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { ListItemIcon } from '../../base'; +import { Link, ListItemIcon } from '../../base'; import { LearningIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; @@ -27,20 +27,23 @@ const LearningSection: React.FC = ({ filteredAcademyData } setAutoUpdate(false); }; - const navigateToLearningPath = (item: string): void => { - window.location.href = `/academy/learning-paths/${slugify('' + item)}`; - }; - const renderLearningItem = (item: string, index: number) => ( - navigateToLearningPath(item)}> - - - - {item} - + + + + + + {item} + + ); return ( diff --git a/src/custom/CatalogDetail/OverviewSection.tsx b/src/custom/CatalogDetail/OverviewSection.tsx index a933226f7..4d842bde7 100644 --- a/src/custom/CatalogDetail/OverviewSection.tsx +++ b/src/custom/CatalogDetail/OverviewSection.tsx @@ -13,34 +13,31 @@ interface OverviewSectionProps { details: Pattern; type: string; cardId: string; - handleClick: (event: React.MouseEvent) => void; title: string; - id: string; - anchorEl: HTMLElement | null; - handleClose: () => void; getUrl: (type: string, id: string) => string; showContentDetails: boolean; ViewsComponent?: React.ReactNode; showVersion: boolean; classes: Class[]; handleCopyUrl: (type: string, name: string, id: string) => void; + fontFamily?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + userProfile?: any; } const OverviewSection: React.FC = ({ details, type, cardId, - handleClick, title, - id, - anchorEl, - handleClose, getUrl, showContentDetails, ViewsComponent, showVersion, classes, - handleCopyUrl + handleCopyUrl, + fontFamily, + userProfile }) => { return ( @@ -49,7 +46,8 @@ const OverviewSection: React.FC = ({ display: 'flex', flexDirection: 'row', width: '100%', - flexWrap: 'wrap' + flexWrap: 'wrap', + fontFamily: fontFamily || 'inherit' }} > {details?.name} @@ -57,11 +55,7 @@ const OverviewSection: React.FC = ({ details={details} type={type} cardId={cardId} - handleClick={handleClick} title={title} - id={id} - anchorEl={anchorEl} - handleClose={handleClose} getUrl={getUrl} handleCopyUrl={handleCopyUrl} /> @@ -69,7 +63,7 @@ const OverviewSection: React.FC = ({ - + {details?.catalog_data?.content_class && ( = ({ /> )} - + diff --git a/src/custom/CatalogDetail/RelatedDesigns.tsx b/src/custom/CatalogDetail/RelatedDesigns.tsx index 5b000b86f..0d5ff5682 100644 --- a/src/custom/CatalogDetail/RelatedDesigns.tsx +++ b/src/custom/CatalogDetail/RelatedDesigns.tsx @@ -2,6 +2,7 @@ import { CatalogCardDesignLogo } from '../CustomCatalog'; import CustomCatalogCard, { Pattern } from '../CustomCatalog/CustomCard'; import { formatToTitleCase } from './helper'; import { AdditionalContainer, ContentHeading, DesignCardContainer } from './style'; +import { UserProfile } from './types'; export interface PatternsPerUser { patterns: Pattern[]; @@ -11,9 +12,17 @@ interface RelatedDesignsProps { details: Pattern; type: string; patternsPerUser: PatternsPerUser; + onSuggestedPatternClick: (pattern: Pattern) => void; + userProfile?: UserProfile; } -const RelatedDesigns: React.FC = ({ details, type, patternsPerUser }) => { +const RelatedDesigns: React.FC = ({ + details, + type, + patternsPerUser, + onSuggestedPatternClick, + userProfile +}) => { const filteredPatternsPerUser = patternsPerUser?.patterns?.filter( (pattern) => pattern.id !== details.id ); @@ -24,15 +33,26 @@ const RelatedDesigns: React.FC = ({ details, type, patterns

- Other published design by {formatToTitleCase(details.user.first_name)} + Other published design by + {formatToTitleCase(userProfile?.first_name ?? '')}

{filteredPatternsPerUser.map((pattern, index) => ( - + onSuggestedPatternClick(pattern)} + UserName={`${userProfile?.first_name ?? ''} ${userProfile?.last_name ?? ''}`} + avatarUrl={userProfile?.avatar_url} + basePath="/static/img/meshmodels" + subBasePath="color" + cardTechnologies={true} + > void; + cardId?: string; title: string; - id?: string; - anchorEl: HTMLElement | null; - handleClose: () => void; getUrl: (type: string, id: string) => string; showContentDetails: boolean; ViewsComponent?: React.ReactNode; @@ -21,19 +17,18 @@ interface RightPanelProps { showCaveats: boolean; classes: Class[]; patternsPerUser: PatternsPerUser; + onSuggestedPatternClick: (pattern: Pattern) => void; handleCopyUrl: (type: string, name: string, id: string) => void; fontFamily?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + useGetUserProfileByIdQuery: any; } const RightPanel: React.FC = ({ details, type, - cardId, - handleClick, + cardId = details.id, title, - id = '', - anchorEl, - handleClose, getUrl, showContentDetails, ViewsComponent, @@ -41,10 +36,15 @@ const RightPanel: React.FC = ({ showCaveats, classes, patternsPerUser, + onSuggestedPatternClick, handleCopyUrl, - fontFamily + fontFamily, + useGetUserProfileByIdQuery }) => { const cleanedType = type.replace('my-', '').replace(/s$/, ''); + const { data: userProfile } = useGetUserProfileByIdQuery({ + id: details.user_id + }); return (
@@ -52,20 +52,24 @@ const RightPanel: React.FC = ({ details={details} type={cleanedType} cardId={cardId} - handleClick={handleClick} title={title} - id={id} - anchorEl={anchorEl} - handleClose={handleClose} getUrl={getUrl} showContentDetails={showContentDetails} ViewsComponent={ViewsComponent} showVersion={showVersion} classes={classes} handleCopyUrl={handleCopyUrl} + fontFamily={fontFamily} + userProfile={userProfile} /> {showCaveats && } - +
); }; From fb42a654b756f141a18d17794ca00eff870f995e Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:53:20 +0530 Subject: [PATCH 12/15] style: update stying based on catalog modal Signed-off-by: Amit Amrutiya --- .../CatalogDetail/SocialSharePopper.tsx | 158 +++++++++++------- src/custom/CatalogDetail/UserInfo.tsx | 12 +- .../CustomCatalog/CatalogCardDesignLogo.tsx | 2 +- src/custom/CustomCatalog/CustomCard.tsx | 2 +- src/custom/Markdown/style.tsx | 3 +- 5 files changed, 107 insertions(+), 70 deletions(-) diff --git a/src/custom/CatalogDetail/SocialSharePopper.tsx b/src/custom/CatalogDetail/SocialSharePopper.tsx index ad6ae2cf3..3c24b32d8 100644 --- a/src/custom/CatalogDetail/SocialSharePopper.tsx +++ b/src/custom/CatalogDetail/SocialSharePopper.tsx @@ -1,21 +1,17 @@ -import { Fade } from '@mui/material'; -import React from 'react'; +import { Box, IconButton, Menu, MenuItem, Tooltip } from '@mui/material'; +import React, { useState } from 'react'; import { FacebookShareButton, LinkedinShareButton, TwitterShareButton } from 'react-share'; -import { ClickAwayListener, IconButton, Paper, Popper, Tooltip } from '../../base'; import { ChainIcon, FacebookIcon, LinkedinIcon, ShareIcon, TwitterIcon } from '../../icons'; import { useTheme } from '../../theme'; import { Pattern } from '../CustomCatalog/CustomCard'; +import { ErrorBoundary } from '../ErrorBoundary'; import { CopyShareIconWrapper, VisibilityChip } from './style'; interface SocialSharePopperProps { details: Pattern; type: string; cardId: string; - handleClick: (event: React.MouseEvent) => void; title: string; - id: string; - anchorEl: HTMLElement | null; - handleClose: () => void; getUrl: (type: string, id: string) => string; handleCopyUrl: (type: string, name: string, id: string) => void; } @@ -24,71 +20,105 @@ const SocialSharePopper: React.FC = ({ details, type, cardId, - handleClick, title, - id, - anchorEl, - handleClose, getUrl, handleCopyUrl }) => { - const cleanedType = type.replace('my-', '').replace(/s$/, ''); const theme = useTheme(); + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + return ( - - - {details?.visibility} - - {details?.visibility !== 'private' && ( - - handleCopyUrl(cleanedType, details?.name, details?.id)} - > - - - - )} - {(details?.visibility === 'published' || details?.visibility === 'public') && ( - <> - - - + + + + {details?.visibility} + + + {details?.visibility !== 'private' && ( + + handleCopyUrl(cleanedType, details?.name, details?.id)} + > + - - {({ TransitionProps }) => ( - - - - - - - - - - - - - - - - )} - - - )} - + )} + + {(details?.visibility === 'published' || details?.visibility === 'public') && ( + <> + + + + + + + + + + + + + + + + + + + + + + + )} + + ); }; diff --git a/src/custom/CatalogDetail/UserInfo.tsx b/src/custom/CatalogDetail/UserInfo.tsx index 6a2222491..602433086 100644 --- a/src/custom/CatalogDetail/UserInfo.tsx +++ b/src/custom/CatalogDetail/UserInfo.tsx @@ -2,21 +2,27 @@ import { Pattern } from '../CustomCatalog/CustomCard'; import { getVersion } from '../CustomCatalog/Helper'; import { formatDate } from './helper'; import { ContentDetailsPoints, ContentDetailsText, ContentRow, RedirectLink } from './style'; +import { UserProfile } from './types'; interface UserInfoProps { details: Pattern; showVersion?: boolean; + userProfile?: UserProfile; } -const UserInfo: React.FC = ({ details, showVersion = true }) => { +const UserInfo: React.FC = ({ details, showVersion = true, userProfile }) => { return ( <> CREATED BY - + - {details.user.first_name} {details?.user?.last_name} + {userProfile?.first_name} {userProfile?.last_name} diff --git a/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx b/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx index 3fb392471..30e3473f4 100644 --- a/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx +++ b/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx @@ -43,7 +43,7 @@ const CatalogCardDesignLogo: React.FC = ({ return ( <> {imgURL && imgURL.length > 0 ? ( -
+
{!imgError ? ( <> = ({ {isDetailed && ( - + ({ export const StyledMarkdownP = styled('p')(({ theme }) => ({ color: theme.palette.text.default, marginBlock: '0px', - ...theme.typography.textB1Regular + ...theme.typography.textB1Regular, + fontFamily: 'inherit' })); export const StyledMarkdownTooltipP = styled('p')(({ theme }) => ({ From 904713fbe64cc2b3a994434b263ae85a3557b150 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:53:44 +0530 Subject: [PATCH 13/15] chore: add new copy icon Signed-off-by: Amit Amrutiya --- src/icons/Copy/CopyIcon.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/icons/Copy/CopyIcon.tsx b/src/icons/Copy/CopyIcon.tsx index e5edf8895..89424292c 100644 --- a/src/icons/Copy/CopyIcon.tsx +++ b/src/icons/Copy/CopyIcon.tsx @@ -10,16 +10,14 @@ interface CopyIconProps { const CopyIcon: React.FC = ({ width, height, fill = 'white', style }) => ( - - - + ); From d3090d7a0697526841d635b588f103ee0aac323d Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 22:09:01 +0530 Subject: [PATCH 14/15] feat: update styling Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/LeftPanel.tsx | 11 ++-------- src/custom/CatalogDetail/RelatedDesigns.tsx | 3 +-- .../CatalogDetail/TechnologySection.tsx | 18 ++++++++--------- src/custom/CatalogDetail/style.tsx | 2 +- src/custom/CustomCatalog/CustomCard.tsx | 7 ++++++- src/custom/CustomCatalog/Helper.ts | 20 ++++++++++++------- src/custom/Typography/index.tsx | 2 +- 7 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/custom/CatalogDetail/LeftPanel.tsx b/src/custom/CatalogDetail/LeftPanel.tsx index af1ac1602..2bb7fbb37 100644 --- a/src/custom/CatalogDetail/LeftPanel.tsx +++ b/src/custom/CatalogDetail/LeftPanel.tsx @@ -15,9 +15,6 @@ interface LeftPanelProps { isCloneLoading: boolean; handleClone: (name: string, id: string) => void; showTechnologies?: boolean; - openTechnologies: boolean; - availableTechnologies: string[]; - handleOpenTechnologies: () => void; mode: string; filteredAcademyData: FilteredAcademyData; isCloneDisabled: boolean; @@ -34,9 +31,6 @@ const LeftPanel: React.FC = ({ isCloneLoading, handleClone, showTechnologies = true, - openTechnologies, - availableTechnologies, - handleOpenTechnologies, mode, filteredAcademyData, isCloneDisabled, @@ -45,6 +39,7 @@ const LeftPanel: React.FC = ({ fontFamily }) => { const theme = useTheme(); + return (
= ({ /> {showTechnologies && ( )} diff --git a/src/custom/CatalogDetail/RelatedDesigns.tsx b/src/custom/CatalogDetail/RelatedDesigns.tsx index 0d5ff5682..fdf8cedf3 100644 --- a/src/custom/CatalogDetail/RelatedDesigns.tsx +++ b/src/custom/CatalogDetail/RelatedDesigns.tsx @@ -33,8 +33,7 @@ const RelatedDesigns: React.FC = ({

- Other published design by - {formatToTitleCase(userProfile?.first_name ?? '')} + Other published design by {formatToTitleCase(userProfile?.first_name ?? '')}

diff --git a/src/custom/CatalogDetail/TechnologySection.tsx b/src/custom/CatalogDetail/TechnologySection.tsx index 2bddd5961..f4cda831f 100644 --- a/src/custom/CatalogDetail/TechnologySection.tsx +++ b/src/custom/CatalogDetail/TechnologySection.tsx @@ -1,24 +1,22 @@ -import React from 'react'; +import React, { useState } from 'react'; import { ListItemIcon } from '../../base'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; import { LabelDiv } from './style'; interface TechnologySectionProps { - availableTechnologies: string[]; - openTechnologies: boolean; - handleOpenTechnologies: () => void; + technologies: string[]; technologySVGPath: string; technologySVGSubpath: string; } const TechnologySection: React.FC = ({ - availableTechnologies, - openTechnologies, - handleOpenTechnologies, technologySVGPath, - technologySVGSubpath + technologySVGSubpath, + technologies }) => { + const [openTechnologies, setOpenTechnologies] = useState(true); + const theme = useTheme(); const renderTechnologyItem = (item: string, index: number) => { @@ -47,8 +45,8 @@ const TechnologySection: React.FC = ({ setOpenTechnologies((prev) => !prev)} + items={technologies} renderItem={renderTechnologyItem} emptyState={'No technologies assigned to this design'} tooltip={'Technologies used in this design'} diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx index f35b8140a..5d6320255 100644 --- a/src/custom/CatalogDetail/style.tsx +++ b/src/custom/CatalogDetail/style.tsx @@ -44,7 +44,7 @@ export const ContentDetailsText = styled(Typography)(({ theme }) => ({ fontSize: '1rem', color: theme.palette.text.default, ['@media (min-width:1200px)']: { - fontSize: '1.3rem' + fontSize: '1' } })); diff --git a/src/custom/CustomCatalog/CustomCard.tsx b/src/custom/CustomCatalog/CustomCard.tsx index 7366d313b..0a1057550 100644 --- a/src/custom/CustomCatalog/CustomCard.tsx +++ b/src/custom/CustomCatalog/CustomCard.tsx @@ -138,7 +138,12 @@ const CustomCatalogCard: React.FC = ({ const version = getVersion(pattern); useEffect(() => { - handleImage(technologies, basePath, subBasePath, setAvailableTechnologies); + handleImage({ + technologies, + basePath, + subBasePath, + setAvailableTechnologies + }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/custom/CustomCatalog/Helper.ts b/src/custom/CustomCatalog/Helper.ts index 10bbc4e31..02c5d0c54 100644 --- a/src/custom/CustomCatalog/Helper.ts +++ b/src/custom/CustomCatalog/Helper.ts @@ -42,16 +42,22 @@ const getValidSvgPaths = async ( return validSvgPaths; }; -export const handleImage = async ( - technologies: string[], - basePath: string = '', - subBasePath: string = '', - setAvailableTechnologies: (technologies: string[]) => void -) => { +interface HandleImageProps { + technologies: string[]; + basePath?: string; + subBasePath?: string; + setAvailableTechnologies: (technologies: string[]) => void; +} + +export const handleImage = async ({ + technologies, + basePath = '', + subBasePath = '', + setAvailableTechnologies +}: HandleImageProps) => { const validSvgPaths = await getValidSvgPaths(technologies, basePath, subBasePath); setAvailableTechnologies(validSvgPaths); }; - export const DEFAULT_DESIGN_VERSION = '0.0.0'; export const getVersion = (design: Pattern) => { diff --git a/src/custom/Typography/index.tsx b/src/custom/Typography/index.tsx index 2f03bb473..011112891 100644 --- a/src/custom/Typography/index.tsx +++ b/src/custom/Typography/index.tsx @@ -140,7 +140,7 @@ export const ContentDetailsPoints = styled(TextB3Regular)(({ theme }) => ({ export const ContentDetailsText = styled(TextB1Regular)(({ theme }) => ({ ...commonTypographyStyles(theme), ['@media (min-width:1200px)']: { - fontSize: '1.3rem' + fontSize: '1' } })); From 1c010efa294123d489ceefa41633aa82432a4bbd Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 30 Oct 2024 10:12:24 +0530 Subject: [PATCH 15/15] feat: show only valid svgs Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/RightPanel.tsx | 4 +-- .../CatalogDetail/TechnologySection.tsx | 28 ++++++++++++++++--- src/custom/CatalogDetail/UserInfo.tsx | 2 +- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/custom/CatalogDetail/RightPanel.tsx b/src/custom/CatalogDetail/RightPanel.tsx index 78e47625e..0c3c8a4d5 100644 --- a/src/custom/CatalogDetail/RightPanel.tsx +++ b/src/custom/CatalogDetail/RightPanel.tsx @@ -17,11 +17,11 @@ interface RightPanelProps { showCaveats: boolean; classes: Class[]; patternsPerUser: PatternsPerUser; - onSuggestedPatternClick: (pattern: Pattern) => void; handleCopyUrl: (type: string, name: string, id: string) => void; - fontFamily?: string; + onSuggestedPatternClick: (pattern: Pattern) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any useGetUserProfileByIdQuery: any; + fontFamily?: string; } const RightPanel: React.FC = ({ diff --git a/src/custom/CatalogDetail/TechnologySection.tsx b/src/custom/CatalogDetail/TechnologySection.tsx index f4cda831f..4018c6255 100644 --- a/src/custom/CatalogDetail/TechnologySection.tsx +++ b/src/custom/CatalogDetail/TechnologySection.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { ListItemIcon } from '../../base'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; @@ -16,15 +16,35 @@ const TechnologySection: React.FC = ({ technologies }) => { const [openTechnologies, setOpenTechnologies] = useState(true); - + const [validTechnologies, setValidTechnologies] = useState([]); const theme = useTheme(); + useEffect(() => { + // Function to check if SVG exists + const validateTechnologies = async () => { + const validTechs = await Promise.all( + technologies.map(async (tech) => { + const svg_path = `/${technologySVGPath}/${tech.toLowerCase()}/${technologySVGSubpath}/${tech.toLowerCase()}-color.svg`; + try { + const response = await fetch(svg_path); + return response.ok ? tech : null; + } catch { + return null; + } + }) + ); + setValidTechnologies(validTechs.filter((tech): tech is string => tech !== null)); + }; + + validateTechnologies(); + }, [technologies, technologySVGPath, technologySVGSubpath]); + const renderTechnologyItem = (item: string, index: number) => { const svg_path = `${technologySVGPath}/${item.toLowerCase()}/${technologySVGSubpath}/${item.toLowerCase()}-color.svg`; return ( - technology icon + {`${item} {item} @@ -46,7 +66,7 @@ const TechnologySection: React.FC = ({ title="TECHNOLOGY" isOpen={openTechnologies} onToggle={() => setOpenTechnologies((prev) => !prev)} - items={technologies} + items={validTechnologies} renderItem={renderTechnologyItem} emptyState={'No technologies assigned to this design'} tooltip={'Technologies used in this design'} diff --git a/src/custom/CatalogDetail/UserInfo.tsx b/src/custom/CatalogDetail/UserInfo.tsx index 602433086..86029f960 100644 --- a/src/custom/CatalogDetail/UserInfo.tsx +++ b/src/custom/CatalogDetail/UserInfo.tsx @@ -21,7 +21,7 @@ const UserInfo: React.FC = ({ details, showVersion = true, userPr target="_blank" rel="noopener noreferrer" > - + {userProfile?.first_name} {userProfile?.last_name}