Skip to content

Commit

Permalink
Merge pull request #776 from amitamrutiya/amit/catalog-detail
Browse files Browse the repository at this point in the history
Create sistent components for catalog detail page
  • Loading branch information
amitamrutiya authored Oct 30, 2024
2 parents dfb799c + bcb4e01 commit 236e54e
Show file tree
Hide file tree
Showing 45 changed files with 2,024 additions and 27 deletions.
82 changes: 81 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
},
"dependencies": {
"js-yaml": "^4.1.0",
"lodash": "^4.17.21"
"lodash": "^4.17.21",
"react-share": "^5.1.0"
}
}
115 changes: 115 additions & 0 deletions src/custom/CatalogDetail/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
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 { 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<ActionButtonsProps> = ({
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 (
<StyledActionWrapper>
{actionItems && (
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: '0.75rem',
width: '100%'
}}
>
<ActionButton
sx={{
borderRadius: '0.2rem',
backgroundColor: 'background.inverse',
gap: '10px',
color: charcoal[100]
}}
onClick={() =>
cleanedType === RESOURCE_TYPES.FILTERS
? downloadFilter(details.id, details.name)
: downloadYaml(details.pattern_file, details.name)
}
>
<Download width={24} height={24} fill={charcoal[100]} />
Download
</ActionButton>

{cleanedType !== RESOURCE_TYPES.FILTERS && (
<ActionButton
sx={{
borderRadius: '0.2rem',
gap: '10px',
color: charcoal[100]
}}
onClick={() => handleClone(details?.name, details?.id)}
disabled={isCloneDisabled}
>
{isCloneLoading ? (
<CircularProgress size={24} color={'inherit'} />
) : (
<>
<CopyIcon width={24} height={24} fill={charcoal[100]} />
Clone
</>
)}
</ActionButton>
)}
</div>
)}
<LinkUrl
style={{ width: '100%' }}
href={`https://playground.meshery.io/extension/meshmap?mode=${mode}&type=${resourcePlaygroundType}&id=${cardId}&name=${slugify(
details.name
)}`}
target="_blank"
rel="noreferrer"
>
<ActionButton
sx={{
borderRadius: '0.2rem',
backgroundColor: 'background.cta.default',
color: charcoal[10],
gap: '10px',
width: '100%'
}}
>
<KanvasIcon width={24} height={24} primaryFill={charcoal[10]} fill={charcoal[10]} />
Open in Playground
</ActionButton>
</LinkUrl>
</StyledActionWrapper>
);
};

export default ActionButtons;
30 changes: 30 additions & 0 deletions src/custom/CatalogDetail/CaveatsSection.tsx
Original file line number Diff line number Diff line change
@@ -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<CaveatsSectionProps> = ({ details }) => {
return (
<CaveatsContainer>
<ContentHeading>
<h2 style={{ margin: '0' }}>CAVEATS AND CONSIDERATIONS</h2>
</ContentHeading>
{details?.catalog_data?.pattern_caveats ? (
<ContentDetailsText style={{ whiteSpace: 'normal', fontFamily: 'inherit' }}>
<RenderMarkdown
content={decodeURIComponent(details.catalog_data.pattern_caveats || '')}
/>
</ContentDetailsText>
) : (
<ContentDetailsText>No caveats registered</ContentDetailsText>
)}
</CaveatsContainer>
);
};

export default CaveatsSection;
74 changes: 74 additions & 0 deletions src/custom/CatalogDetail/ChallengesSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useEffect, useState } from 'react';
import { Link, ListItemIcon } from '../../base';
import { ChallengesIcon } from '../../icons';
import { useTheme } from '../../theme';
import CollapsibleSection from './CollapsibleSection';
import { slugify } from './helper';
import { LabelDiv } from './style';
import { FilteredAcademyData } from './types';

interface ChallengesSectionProps {
filteredAcademyData: FilteredAcademyData;
}

const ChallengesSection: React.FC<ChallengesSectionProps> = ({ 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 renderChallengeItem = (item: string, index: number) => (
<Link
href={`https://meshery.layer5.io/academy/challenges/${slugify('' + item)}`}
target="_blank"
rel="noopener noreferrer"
style={{ textDecoration: 'none', color: 'inherit' }}
>
<LabelDiv key={index} clickable={true}>
<ListItemIcon sx={{ minWidth: '1.5rem', marginRight: 1 }}>
<ChallengesIcon
primaryFill={theme.palette.icon.default}
secondaryFill={theme.palette.icon.secondary}
brandFill={theme.palette.icon.secondary}
/>
</ListItemIcon>
{item}
</LabelDiv>
</Link>
);

return (
<>
<hr
style={{
backgroundColor: theme.palette.background.secondary,
border: 'none',
height: '1px',
marginTop: '1rem',
marginBottom: '1rem'
}}
/>
<CollapsibleSection
title="Challenges"
isOpen={openChallenges}
onToggle={toggleOpenChallenges}
items={filteredAcademyData['challenge'] ?? []}
renderItem={renderChallengeItem}
tooltip="Learn CNCF projects by taking and completing time-based, hands-on labs. [Browse all challenges](/academy/challenges)"
emptyState="No active challenges for this technology"
/>
</>
);
};

export default ChallengesSection;
Loading

0 comments on commit 236e54e

Please sign in to comment.