Skip to content

Commit 236e54e

Browse files
authored
Merge pull request #776 from amitamrutiya/amit/catalog-detail
Create sistent components for catalog detail page
2 parents dfb799c + bcb4e01 commit 236e54e

45 files changed

Lines changed: 2024 additions & 27 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package-lock.json

Lines changed: 81 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
},
118118
"dependencies": {
119119
"js-yaml": "^4.1.0",
120-
"lodash": "^4.17.21"
120+
"lodash": "^4.17.21",
121+
"react-share": "^5.1.0"
121122
}
122123
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import _ from 'lodash';
2+
import React from 'react';
3+
import { CircularProgress } from '../../base';
4+
import { CopyIcon, KanvasIcon } from '../../icons';
5+
import Download from '../../icons/Download/Download';
6+
import { charcoal } from '../../theme';
7+
import { Pattern } from '../CustomCatalog/CustomCard';
8+
import { downloadFilter, downloadYaml, slugify } from './helper';
9+
import { ActionButton, LinkUrl, StyledActionWrapper } from './style';
10+
import { RESOURCE_TYPES } from './types';
11+
12+
interface ActionButtonsProps {
13+
actionItems: boolean;
14+
details: Pattern;
15+
type: string;
16+
cardId: string;
17+
isCloneLoading: boolean;
18+
handleClone: (name: string, id: string) => void;
19+
mode: string;
20+
isCloneDisabled: boolean;
21+
}
22+
23+
const ActionButtons: React.FC<ActionButtonsProps> = ({
24+
actionItems,
25+
details,
26+
type,
27+
cardId,
28+
isCloneLoading,
29+
handleClone,
30+
mode,
31+
isCloneDisabled
32+
}) => {
33+
const cleanedType = type.replace('my-', '').replace(/s$/, '');
34+
const resourcePlaygroundType = Object.values({
35+
..._.omit(RESOURCE_TYPES, ['FILTERS']),
36+
CATALOG: 'catalog'
37+
}).includes(cleanedType)
38+
? cleanedType
39+
: 'design';
40+
return (
41+
<StyledActionWrapper>
42+
{actionItems && (
43+
<div
44+
style={{
45+
display: 'flex',
46+
flexDirection: 'row',
47+
gap: '0.75rem',
48+
width: '100%'
49+
}}
50+
>
51+
<ActionButton
52+
sx={{
53+
borderRadius: '0.2rem',
54+
backgroundColor: 'background.inverse',
55+
gap: '10px',
56+
color: charcoal[100]
57+
}}
58+
onClick={() =>
59+
cleanedType === RESOURCE_TYPES.FILTERS
60+
? downloadFilter(details.id, details.name)
61+
: downloadYaml(details.pattern_file, details.name)
62+
}
63+
>
64+
<Download width={24} height={24} fill={charcoal[100]} />
65+
Download
66+
</ActionButton>
67+
68+
{cleanedType !== RESOURCE_TYPES.FILTERS && (
69+
<ActionButton
70+
sx={{
71+
borderRadius: '0.2rem',
72+
gap: '10px',
73+
color: charcoal[100]
74+
}}
75+
onClick={() => handleClone(details?.name, details?.id)}
76+
disabled={isCloneDisabled}
77+
>
78+
{isCloneLoading ? (
79+
<CircularProgress size={24} color={'inherit'} />
80+
) : (
81+
<>
82+
<CopyIcon width={24} height={24} fill={charcoal[100]} />
83+
Clone
84+
</>
85+
)}
86+
</ActionButton>
87+
)}
88+
</div>
89+
)}
90+
<LinkUrl
91+
style={{ width: '100%' }}
92+
href={`https://playground.meshery.io/extension/meshmap?mode=${mode}&type=${resourcePlaygroundType}&id=${cardId}&name=${slugify(
93+
details.name
94+
)}`}
95+
target="_blank"
96+
rel="noreferrer"
97+
>
98+
<ActionButton
99+
sx={{
100+
borderRadius: '0.2rem',
101+
backgroundColor: 'background.cta.default',
102+
color: charcoal[10],
103+
gap: '10px',
104+
width: '100%'
105+
}}
106+
>
107+
<KanvasIcon width={24} height={24} primaryFill={charcoal[10]} fill={charcoal[10]} />
108+
Open in Playground
109+
</ActionButton>
110+
</LinkUrl>
111+
</StyledActionWrapper>
112+
);
113+
};
114+
115+
export default ActionButtons;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react';
2+
import { Pattern } from '../CustomCatalog/CustomCard';
3+
import { RenderMarkdown } from '../Markdown';
4+
import { ContentDetailsText } from '../Typography';
5+
import { CaveatsContainer, ContentHeading } from './style';
6+
7+
interface CaveatsSectionProps {
8+
details: Pattern;
9+
}
10+
11+
const CaveatsSection: React.FC<CaveatsSectionProps> = ({ details }) => {
12+
return (
13+
<CaveatsContainer>
14+
<ContentHeading>
15+
<h2 style={{ margin: '0' }}>CAVEATS AND CONSIDERATIONS</h2>
16+
</ContentHeading>
17+
{details?.catalog_data?.pattern_caveats ? (
18+
<ContentDetailsText style={{ whiteSpace: 'normal', fontFamily: 'inherit' }}>
19+
<RenderMarkdown
20+
content={decodeURIComponent(details.catalog_data.pattern_caveats || '')}
21+
/>
22+
</ContentDetailsText>
23+
) : (
24+
<ContentDetailsText>No caveats registered</ContentDetailsText>
25+
)}
26+
</CaveatsContainer>
27+
);
28+
};
29+
30+
export default CaveatsSection;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { useEffect, useState } from 'react';
2+
import { Link, ListItemIcon } from '../../base';
3+
import { ChallengesIcon } from '../../icons';
4+
import { useTheme } from '../../theme';
5+
import CollapsibleSection from './CollapsibleSection';
6+
import { slugify } from './helper';
7+
import { LabelDiv } from './style';
8+
import { FilteredAcademyData } from './types';
9+
10+
interface ChallengesSectionProps {
11+
filteredAcademyData: FilteredAcademyData;
12+
}
13+
14+
const ChallengesSection: React.FC<ChallengesSectionProps> = ({ filteredAcademyData }) => {
15+
const theme = useTheme();
16+
const [openChallenges, setOpenChallenges] = useState(false);
17+
const [autoUpdate, setAutoUpdate] = useState(true);
18+
19+
useEffect(() => {
20+
if (autoUpdate) {
21+
setOpenChallenges((filteredAcademyData?.['challenges'] ?? []).length > 0);
22+
}
23+
}, [filteredAcademyData, autoUpdate]);
24+
25+
const toggleOpenChallenges = () => {
26+
setOpenChallenges((prev) => !prev);
27+
setAutoUpdate(false);
28+
};
29+
30+
const renderChallengeItem = (item: string, index: number) => (
31+
<Link
32+
href={`https://meshery.layer5.io/academy/challenges/${slugify('' + item)}`}
33+
target="_blank"
34+
rel="noopener noreferrer"
35+
style={{ textDecoration: 'none', color: 'inherit' }}
36+
>
37+
<LabelDiv key={index} clickable={true}>
38+
<ListItemIcon sx={{ minWidth: '1.5rem', marginRight: 1 }}>
39+
<ChallengesIcon
40+
primaryFill={theme.palette.icon.default}
41+
secondaryFill={theme.palette.icon.secondary}
42+
brandFill={theme.palette.icon.secondary}
43+
/>
44+
</ListItemIcon>
45+
{item}
46+
</LabelDiv>
47+
</Link>
48+
);
49+
50+
return (
51+
<>
52+
<hr
53+
style={{
54+
backgroundColor: theme.palette.background.secondary,
55+
border: 'none',
56+
height: '1px',
57+
marginTop: '1rem',
58+
marginBottom: '1rem'
59+
}}
60+
/>
61+
<CollapsibleSection
62+
title="Challenges"
63+
isOpen={openChallenges}
64+
onToggle={toggleOpenChallenges}
65+
items={filteredAcademyData['challenge'] ?? []}
66+
renderItem={renderChallengeItem}
67+
tooltip="Learn CNCF projects by taking and completing time-based, hands-on labs. [Browse all challenges](/academy/challenges)"
68+
emptyState="No active challenges for this technology"
69+
/>
70+
</>
71+
);
72+
};
73+
74+
export default ChallengesSection;

0 commit comments

Comments
 (0)