diff --git a/components/md-renderer/mdx-components/a.tsx b/components/md-renderer/mdx-components/a.tsx index 93ad530cd..5a55ce269 100644 --- a/components/md-renderer/mdx-components/a.tsx +++ b/components/md-renderer/mdx-components/a.tsx @@ -3,8 +3,8 @@ import styled from 'styled-components'; type EnrichedLinkProps = { href: string; - children: React.ReactNode -} + children: React.ReactNode; +}; const Link = styled.a` font-weight: 600; @@ -13,14 +13,25 @@ const Link = styled.a` const EnrichedLink = (props: EnrichedLinkProps) => { // Is external URL or is a media URL - const isExternalUrl = /(^http(s)?:\/\/)|(\.(png|svg|jpeg|jpg)$)/.test(props.href); + const isExternalUrl = /(^http(s)?:\/\/)|(\.(png|svg|jpeg|jpg)$)/.test( + props.href + ); + + const linkProps: Record = { + target: '_self', + ...(isExternalUrl + ? { + rel: 'nofollow', + target: '_blank', + } + : {}), + }; return ( - + {props.children} ); }; export default EnrichedLink; - diff --git a/components/md-renderer/mdx-components/badge-link.tsx b/components/md-renderer/mdx-components/badge-link.tsx index b4a6cb200..9de1d4538 100644 --- a/components/md-renderer/mdx-components/badge-link.tsx +++ b/components/md-renderer/mdx-components/badge-link.tsx @@ -6,16 +6,46 @@ type BadgeLinkType = { badgeText: string; href: string; colorScheme?: string; - children: React.ReactNode + children: React.ReactNode; }; export function BadgeLink(props: BadgeLinkType) { - const { target = '_blank', colorScheme='purple', badgeText, href, children } = props; + const { + target = '_blank', + colorScheme = 'purple', + badgeText, + href, + children, + } = props; + + // Is external URL or is a media URL + const isExternalUrl = /(^http(s)?:\/\/)|(\.(png|svg|jpeg|jpg)$)/.test( + props.href + ); + + const linkProps: Record = { + ...(isExternalUrl + ? { + rel: 'nofollow', + } + : {}), + }; return ( - - {badgeText} + + + {badgeText} + {children} diff --git a/scripts/sitemap.js b/scripts/sitemap.js index ae13295fe..5c1885a86 100644 --- a/scripts/sitemap.js +++ b/scripts/sitemap.js @@ -18,7 +18,7 @@ const xmlHeader = ` `; // Wrap all pages in tags -const xmlUrlWrapper = nodes => `${xmlHeader} +const xmlUrlWrapper = (nodes) => `${xmlHeader} ${nodes} `; @@ -28,23 +28,17 @@ function getSlugPriority(pageSlug) { } const slugPriorities = [ - [ - '/roadmaps', - '/guides', - '/watch', - '/podcasts' - ], // 1.0 + ['/roadmaps', '/guides', '/watch', '/podcasts'], // 1.0 ['/signup'], // 0.9 - ['/about'] // 0.8 + ['/about'], // 0.8 ]; - const foundIndex = slugPriorities.findIndex( - routes => routes.some(route => pageSlug.startsWith(route)) + const foundIndex = slugPriorities.findIndex((routes) => + routes.some((route) => pageSlug.startsWith(route)) ); if (foundIndex !== -1) { - return parseFloat((10 - foundIndex) / 10) - .toFixed(1); + return parseFloat((10 - foundIndex) / 10).toFixed(1); } return 0.5; @@ -53,15 +47,15 @@ function getSlugPriority(pageSlug) { function getPageRoutes() { const files = glob.sync(`${PAGES_PATH}/**/*.tsx`, { ignore: [ - '**/_*.tsx', // private non-page files e.g. _document.js - '**/[[]*[]].tsx', // Ignore dynamic pages i.e. `page/[something].js` files - '**/[[]*[]]/*.tsx', // Ignore files inside dynamic pages i.e. `[something]/abc.js` - '**/components/*.tsx' // Ignore the component files - ] + '**/_*.tsx', // private non-page files e.g. _document.js + '**/[[]*[]].tsx', // Ignore dynamic pages i.e. `page/[something].js` files + '**/[[]*[]]/*.tsx', // Ignore files inside dynamic pages i.e. `[something]/abc.js` + '**/components/*.tsx', // Ignore the component files + ], }); const pageRoutes = {}; - files.forEach(file => { + files.forEach((file) => { const pageName = file.replace(PAGES_PATH, '').replace('.tsx', ''); const pagePath = pageName.replace('/index', '') || '/'; @@ -78,7 +72,7 @@ function generateNode(nodeProps) { fileName, priority = null, date = null, - frequency = 'monthly' + frequency = 'monthly', } = nodeProps; const pagePath = path.join(basePath, fileName); @@ -87,7 +81,7 @@ function generateNode(nodeProps) { pageStats = fs.lstatSync(pagePath); } catch (e) { console.log(`File not found: ${pagePath}`); - pageStats = { mtime: (new Date()) }; + pageStats = { mtime: new Date() }; } return ` @@ -100,27 +94,25 @@ function generateNode(nodeProps) { function generateSiteMap() { const pageRoutes = getPageRoutes(); - const pageSlugs = Object.keys(pageRoutes) - .filter(route => ![ - '/privacy', - '/terms' - ].includes(route)); + const pageSlugs = Object.keys(pageRoutes).filter( + (route) => !['/privacy', '/terms'].includes(route) + ); - const pagesChunk = pageSlugs.map(pageSlug => { + const pagesChunk = pageSlugs.map((pageSlug) => { return generateNode({ basePath: PAGES_DIR, fileName: `${pageRoutes[pageSlug].page}.tsx`, - slug: pageSlug + slug: pageSlug, }); }); - const guidesChunk = guides.map(guide => { + const guidesChunk = guides.map((guide) => { return generateNode({ basePath: GUIDES_PATH, fileName: `${guide.id}.md`, slug: `/guides/${guide.id}`, date: guide.updatedAt, - priority: '1.0' + priority: '1.0', }); }); @@ -130,21 +122,19 @@ function generateSiteMap() { fileName: roadmap.metaPath.replace('/roadmaps', ''), slug: `/${roadmap.id}`, date: roadmap.updatedAt, - priority: '1.0' + priority: '1.0', }); }); - const nodes = [ - ...roadmapsChunk, - ...guidesChunk, - ...pagesChunk - ]; + const nodes = [...roadmapsChunk, ...guidesChunk, ...pagesChunk]; const sitemap = `${xmlUrlWrapper(nodes.join('\n'))}`; fs.writeFileSync(SITEMAP_PATH, sitemap); - console.log(`sitemap.xml with ${nodes.length} entries was written to ${SITEMAP_PATH}`); + console.log( + `sitemap.xml with ${nodes.length} entries was written to ${SITEMAP_PATH}` + ); } generateSiteMap();