Skip to content

Commit bf8f47b

Browse files
authored
Merge pull request #762 from amitamrutiya/catalogcard
Add new image and catalog empty card
2 parents 21bed8a + 4bc1b00 commit bf8f47b

18 files changed

Lines changed: 338 additions & 119 deletions

File tree

package-lock.json

Lines changed: 2 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
"access": "public"
117117
},
118118
"dependencies": {
119+
"js-yaml": "^4.1.0",
119120
"lodash": "^4.17.21"
120121
}
121122
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React, { useState } from 'react';
2+
import { Dialog } from '../../base';
3+
import { DesignIcon, MesheryFilterIcon } from '../../icons';
4+
5+
interface CatalogCardDesignLogoProps {
6+
zoomEffect?: boolean;
7+
imgURL?: string[];
8+
type: { type: string };
9+
width: string;
10+
height: string;
11+
style?: React.CSSProperties;
12+
}
13+
14+
const CatalogCardDesignLogo: React.FC<CatalogCardDesignLogoProps> = ({
15+
zoomEffect = false,
16+
imgURL,
17+
type,
18+
width,
19+
height,
20+
style = {}
21+
}) => {
22+
const [imgError, setImgError] = useState(false);
23+
const [isZoomed, setIsZoomed] = useState(false);
24+
25+
const handleZoomClick = () => {
26+
if (zoomEffect) {
27+
setIsZoomed(true);
28+
}
29+
};
30+
31+
const handleZoomClose = () => {
32+
setIsZoomed(false);
33+
};
34+
35+
const SvgComponent: React.FC<{ type: { type: string } }> = ({ type }) => {
36+
return type.type === 'filter' ? (
37+
<MesheryFilterIcon width={width} height={height} style={style} />
38+
) : (
39+
<DesignIcon width={width} height={height} style={style} />
40+
);
41+
};
42+
43+
return (
44+
<>
45+
{imgURL && imgURL.length > 0 ? (
46+
<div style={{ width: '100%', height: '7.5rem', position: 'relative' }}>
47+
{!imgError ? (
48+
<>
49+
<img
50+
src={imgURL[0]}
51+
alt="Design SnapShot"
52+
loading="lazy"
53+
onClick={handleZoomClick}
54+
onError={() => setImgError(true)}
55+
style={{
56+
cursor: 'pointer',
57+
width: '100%',
58+
height: '100%',
59+
objectFit: 'cover'
60+
}}
61+
/>
62+
<Dialog
63+
open={isZoomed}
64+
onClose={handleZoomClose}
65+
style={{
66+
backgroundColor: 'rgba(0, 0, 0, 0.8)'
67+
}}
68+
PaperProps={{
69+
style: {
70+
background: 'transparent',
71+
boxShadow: 'none',
72+
overflow: 'hidden',
73+
maxWidth: '60vw'
74+
}
75+
}}
76+
>
77+
<img
78+
src={imgURL[0]}
79+
alt="Zoomed Design SnapShot"
80+
style={{ objectFit: 'contain', maxWidth: '100%', maxHeight: '100%' }}
81+
/>
82+
</Dialog>
83+
</>
84+
) : (
85+
<SvgComponent type={type} />
86+
)}
87+
</div>
88+
) : (
89+
<SvgComponent type={type} />
90+
)}
91+
</>
92+
);
93+
};
94+
95+
export default CatalogCardDesignLogo;
Lines changed: 34 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon }
66
import VerificationClassIcon from '../../icons/ContentClassIcons/VerificationClassIcon';
77
import DeploymentsIcon from '../../icons/Deployments/DeploymentsIcon';
88
import { DownloadIcon } from '../../icons/Download';
9+
import { DARK_TEAL, useTheme } from '../../theme';
10+
import { SNOW_WHITE } from '../../theme/colors/colors';
911
import { CustomTooltip } from '../CustomTooltip';
12+
import { getVersion, handleImage } from './Helper';
1013
import {
1114
CardBack,
1215
CardFront,
@@ -35,7 +38,10 @@ export const DesignCardUrl = styled('a')(() => ({
3538
textDecoration: 'none'
3639
}));
3740

38-
interface Pattern {
41+
export interface Pattern {
42+
id: string;
43+
user_id: string;
44+
pattern_file: string;
3945
name: string;
4046
download_count: number;
4147
clone_count: number;
@@ -51,8 +57,10 @@ interface Pattern {
5157
};
5258
catalog_data?: {
5359
content_class?: string;
54-
imageURL?: string;
60+
imageURL?: string[];
5561
compatibility?: string[];
62+
published_version?: string;
63+
type?: string;
5664
};
5765
visibility: string;
5866
updated_at: Date;
@@ -61,21 +69,15 @@ interface Pattern {
6169
type CatalogCardProps = {
6270
pattern: Pattern;
6371
patternType: string;
64-
cardLink: string;
6572
cardHeight: string;
6673
cardWidth: string;
6774
cardStyles: React.CSSProperties;
68-
version?: string;
6975
avatarUrl: string;
7076
shouldFlip?: boolean;
7177
cardTechnologies?: boolean;
7278
isDetailed?: boolean;
73-
cardAvatarUrl?: boolean;
74-
date?: boolean;
75-
cardVersion?: boolean;
7679
UserName?: string;
7780
children?: React.ReactNode; // catalogImage
78-
TechnologyComponent?: React.ReactNode;
7981
basePath?: string; // path of meshmodel img stored
8082
subBasePath?: string; // path of meshmodel img stored
8183
getHostUrl?: () => string;
@@ -109,7 +111,6 @@ const CustomCatalogCard: React.FC<CatalogCardProps> = ({
109111
shouldFlip,
110112
isDetailed,
111113
cardTechnologies,
112-
cardVersion,
113114
avatarUrl,
114115
UserName,
115116
children,
@@ -123,45 +124,15 @@ const CustomCatalogCard: React.FC<CatalogCardProps> = ({
123124
width: cardWidth,
124125
...cardStyles
125126
};
127+
const theme = useTheme();
126128

127-
const technologies = pattern.catalog_data?.compatibility || []; // an array
129+
const technologies = pattern.catalog_data?.compatibility || [];
128130
const techlimit = 5;
129131
const [availableTechnologies, setAvailableTechnologies] = useState<string[]>([]);
130-
const checkImageUrlValidity = async (url: string, appendHostUrl = true) => {
131-
return new Promise((resolve) => {
132-
const img = new Image();
133-
// Only append host if the URL does not start with "http" or "https"
134-
if (appendHostUrl && !url.startsWith('http')) {
135-
img.src = (getHostUrl ? getHostUrl() : '') + url;
136-
} else {
137-
img.src = url;
138-
}
139-
img.onload = () => {
140-
// Check if the image loaded successfully
141-
resolve(true);
142-
};
132+
const version = getVersion(pattern);
143133

144-
img.onerror = () => {
145-
// Handle the case where the image could not be loaded
146-
resolve(false);
147-
};
148-
});
149-
};
150-
151-
const handleImage = async () => {
152-
const validSvgPaths = [];
153-
for (const technology of technologies) {
154-
const svgIconPath = `${basePath}/${technology.toLowerCase()}/${subBasePath}/${technology.toLowerCase()}-color.svg`;
155-
const isSvgPathValid = await checkImageUrlValidity(svgIconPath as string);
156-
if (isSvgPathValid) {
157-
validSvgPaths.push(technology);
158-
}
159-
}
160-
161-
setAvailableTechnologies(validSvgPaths);
162-
};
163134
useEffect(() => {
164-
handleImage();
135+
handleImage(technologies, basePath, subBasePath, setAvailableTechnologies);
165136
// eslint-disable-next-line react-hooks/exhaustive-deps
166137
}, []);
167138

@@ -196,7 +167,8 @@ const CustomCatalogCard: React.FC<CatalogCardProps> = ({
196167
<DesignDetailsDiv>
197168
<div
198169
style={{
199-
background: 'rgba(231, 239, 243, 0.40)',
170+
background:
171+
theme.palette.mode === 'light' ? 'rgba(231, 239, 243, 0.4)' : 'transparent',
200172
display: 'flex',
201173
alignItems: 'center',
202174
justifyContent: 'center',
@@ -210,26 +182,22 @@ const CustomCatalogCard: React.FC<CatalogCardProps> = ({
210182
</DesignDetailsDiv>
211183
{isDetailed && (
212184
<MetricsContainerFront isDetailed={isDetailed}>
213-
<MetricsDiv>
214-
<DownloadIcon width={18} height={18} />
215-
<MetricsCount>{pattern.download_count}</MetricsCount>
216-
</MetricsDiv>
217-
<MetricsDiv>
218-
<CloneIcon width={18} height={18} fill={'#51636B'} />
219-
<MetricsCount>{pattern.clone_count}</MetricsCount>
220-
</MetricsDiv>
221-
<MetricsDiv>
222-
<OpenIcon width={18} height={18} fill={'#51636B'} />
223-
<MetricsCount>{pattern.view_count}</MetricsCount>
224-
</MetricsDiv>
225-
<MetricsDiv>
226-
<DeploymentsIcon width={18} height={18} />
227-
<MetricsCount>{pattern.deployment_count}</MetricsCount>
228-
</MetricsDiv>
229-
<MetricsDiv>
230-
<ShareIcon width={18} height={18} fill={'#51636B'} />
231-
<MetricsCount>{pattern.share_count}</MetricsCount>
232-
</MetricsDiv>
185+
{[
186+
{ Icon: DownloadIcon, count: pattern.download_count },
187+
{ Icon: CloneIcon, count: pattern.clone_count },
188+
{ Icon: OpenIcon, count: pattern.view_count },
189+
{ Icon: DeploymentsIcon, count: pattern.deployment_count },
190+
{ Icon: ShareIcon, count: pattern.share_count }
191+
].map(({ Icon, count }, index) => (
192+
<MetricsDiv key={index}>
193+
<Icon
194+
width={18}
195+
height={18}
196+
fill={theme.palette.mode === 'light' ? DARK_TEAL : SNOW_WHITE}
197+
/>
198+
<MetricsCount>{count}</MetricsCount>
199+
</MetricsDiv>
200+
))}
233201
</MetricsContainerFront>
234202
)}
235203
</CardFront>
@@ -335,9 +303,9 @@ const CustomCatalogCard: React.FC<CatalogCardProps> = ({
335303
</Grid>
336304
</DesignDetailsDiv>
337305
)}
338-
{cardVersion && (
306+
{version && (
339307
<VersionDiv>
340-
<VersionText>v{cardVersion}</VersionText>
308+
<VersionText>v{version}</VersionText>
341309
</VersionDiv>
342310
)}
343311
</CardBack>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { FC } from 'react';
2+
import { EmptyStyleIcon } from '../../icons/EmptyStyle';
3+
import { useTheme } from '../../theme';
4+
import { CatalogEmptyStateDiv } from './style';
5+
6+
const EmptyStateCard: FC = () => {
7+
const theme = useTheme();
8+
return (
9+
<CatalogEmptyStateDiv>
10+
<EmptyStyleIcon fill={theme.palette.text.default} width="100px" height="100px" />
11+
<h3 style={{ color: theme.palette.text.default }}>No match found</h3>
12+
</CatalogEmptyStateDiv>
13+
);
14+
};
15+
16+
export default EmptyStateCard;

0 commit comments

Comments
 (0)