parent
c7302d7484
commit
359f5d6a4d
10 changed files with 179 additions and 39 deletions
@ -0,0 +1,32 @@ |
|||||||
|
--- |
||||||
|
import type { RoadmapFileType } from '../lib/roadmap'; |
||||||
|
|
||||||
|
export interface Props { |
||||||
|
url: string; |
||||||
|
title: string; |
||||||
|
description: string; |
||||||
|
isNew: boolean; |
||||||
|
} |
||||||
|
|
||||||
|
const { url, title, description, isNew } = Astro.props; |
||||||
|
--- |
||||||
|
|
||||||
|
<a |
||||||
|
href={url} |
||||||
|
class='bg-gradient-to-r from-slate-900 to-amber-900 hover:from-stone-900 hover:to-stone-900 hover:bg-gray-100 flex flex-col p-2.5 sm:p-5 rounded-md sm:rounded-lg border border-gray-200 relative h-full' |
||||||
|
> |
||||||
|
<span |
||||||
|
class='font-regular sm:font-medium text-md sm:text-xl hover:text-gray-50 text-gray-200 sm:text-gray-100 mb-0 sm:mb-1.5' |
||||||
|
> |
||||||
|
{title} |
||||||
|
</span> |
||||||
|
<span class='text-sm leading-normal text-gray-400 hidden sm:block'>{description}</span> |
||||||
|
|
||||||
|
{ |
||||||
|
isNew && ( |
||||||
|
<span class='absolute bottom-1 right-1 bg-yellow-300 text-yellow-900 text-xs font-medium px-1 sm:px-1.5 py-0.5 rounded-sm uppercase'> |
||||||
|
New |
||||||
|
</span> |
||||||
|
) |
||||||
|
} |
||||||
|
</a> |
@ -1,31 +0,0 @@ |
|||||||
--- |
|
||||||
import type { RoadmapFileType } from '../lib/roadmap'; |
|
||||||
|
|
||||||
export interface Props { |
|
||||||
roadmap: RoadmapFileType; |
|
||||||
} |
|
||||||
|
|
||||||
const { roadmap } = Astro.props; |
|
||||||
const frontmatter = roadmap.frontmatter; |
|
||||||
--- |
|
||||||
|
|
||||||
<a |
|
||||||
href={`/${roadmap.id}`} |
|
||||||
class="bg-gradient-to-r from-slate-900 to-amber-900 hover:from-stone-900 hover:to-stone-900 hover:bg-gray-100 flex flex-col p-2.5 sm:p-5 rounded-md sm:rounded-lg border border-gray-200 relative h-full" |
|
||||||
> |
|
||||||
<span |
|
||||||
class="font-regular sm:font-medium text-md sm:text-xl hover:text-gray-50 text-gray-200 sm:text-gray-100 mb-0 sm:mb-1.5" |
|
||||||
>{frontmatter.title}</span |
|
||||||
> |
|
||||||
<span class="text-sm leading-normal text-gray-400 hidden sm:block" |
|
||||||
>{frontmatter.description}</span |
|
||||||
> |
|
||||||
|
|
||||||
{ |
|
||||||
frontmatter.isNew && ( |
|
||||||
<span class="absolute bottom-1 right-1 bg-yellow-300 text-yellow-900 text-xs font-medium px-1 sm:px-1.5 py-0.5 rounded-sm uppercase"> |
|
||||||
New |
|
||||||
</span> |
|
||||||
) |
|
||||||
} |
|
||||||
</a> |
|
@ -0,0 +1,74 @@ |
|||||||
|
import type { MarkdownFileType } from './file'; |
||||||
|
import type { SponsorType } from '../components/Sponsor/Sponsor.astro'; |
||||||
|
|
||||||
|
export interface BestPracticeFrontmatter { |
||||||
|
jsonUrl: string; |
||||||
|
pdfUrl: string; |
||||||
|
order: number; |
||||||
|
featuredTitle: string; |
||||||
|
featuredDescription: string; |
||||||
|
title: string; |
||||||
|
description: string; |
||||||
|
isNew: boolean; |
||||||
|
isUpcoming: boolean; |
||||||
|
dimensions?: { |
||||||
|
width: number; |
||||||
|
height: number; |
||||||
|
}; |
||||||
|
sponsor?: SponsorType; |
||||||
|
seo: { |
||||||
|
title: string; |
||||||
|
description: string; |
||||||
|
keywords: string[]; |
||||||
|
}; |
||||||
|
schema?: { |
||||||
|
headline: string; |
||||||
|
description: string; |
||||||
|
datePublished: string; |
||||||
|
dateModified: string; |
||||||
|
imageUrl: string; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
export type BestPracticeFileType = MarkdownFileType<BestPracticeFrontmatter> & { |
||||||
|
id: string; |
||||||
|
}; |
||||||
|
|
||||||
|
function bestPracticePathToId(filePath: string): string { |
||||||
|
const fileName = filePath.split('/').pop() || ''; |
||||||
|
|
||||||
|
return fileName.replace('.md', ''); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets the IDs of all the best practices available on the website |
||||||
|
* |
||||||
|
* @returns string[] Array of best practices file IDs |
||||||
|
*/ |
||||||
|
export async function getBestPracticeIds() { |
||||||
|
const bestPracticeFiles = await import.meta.glob<BestPracticeFileType>('/src/best-practices/*/*.md', { |
||||||
|
eager: true, |
||||||
|
}); |
||||||
|
|
||||||
|
return Object.keys(bestPracticeFiles).map(bestPracticePathToId); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets all the best practice files |
||||||
|
* |
||||||
|
* @param tag Tag assigned to best practice |
||||||
|
* @returns Promisified BestPracticeFileType[] |
||||||
|
*/ |
||||||
|
export async function getAllBestPractices(): Promise<BestPracticeFileType[]> { |
||||||
|
const bestPracticeFilesMap = await import.meta.glob<BestPracticeFileType>('/src/best-practices/*/*.md', { |
||||||
|
eager: true, |
||||||
|
}); |
||||||
|
|
||||||
|
const bestPracticeFiles = Object.values(bestPracticeFilesMap); |
||||||
|
const bestPracticeItems = bestPracticeFiles.map((bestPracticeFile) => ({ |
||||||
|
...bestPracticeFile, |
||||||
|
id: bestPracticePathToId(bestPracticeFile.file), |
||||||
|
})); |
||||||
|
|
||||||
|
return bestPracticeItems.sort((a, b) => a.frontmatter.order - b.frontmatter.order); |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
--- |
||||||
|
import GridItem from '../../components/GridItem.astro'; |
||||||
|
import SimplePageHeader from '../../components/SimplePageHeader.astro'; |
||||||
|
import BaseLayout from '../../layouts/BaseLayout.astro'; |
||||||
|
import { getAllBestPractices } from '../../lib/best-pratice'; |
||||||
|
|
||||||
|
const bestPractices = await getAllBestPractices(); |
||||||
|
--- |
||||||
|
|
||||||
|
<BaseLayout |
||||||
|
title='Best Practices' |
||||||
|
description={'Step by step guides and paths to learn different tools or technologies'} |
||||||
|
permalink={'/best-practices'} |
||||||
|
> |
||||||
|
<SimplePageHeader |
||||||
|
title='Best Practices' |
||||||
|
description='Step by step guides and paths to learn different tools or technologies' |
||||||
|
showYouTubeAlert={true} |
||||||
|
/> |
||||||
|
|
||||||
|
<div class='bg-gray-100 pt-4 pb-14 sm:pt-8 sm:pb-16'> |
||||||
|
<div class='container'> |
||||||
|
<div class='grid grid-cols-1 sm:grid-cols-2 gap-0.5 sm:gap-3'> |
||||||
|
{ |
||||||
|
bestPractices.map((bestPractice) => ( |
||||||
|
<GridItem |
||||||
|
url={`/best-practices/${bestPractice.id}`} |
||||||
|
isNew={bestPractice.frontmatter.isNew} |
||||||
|
title={bestPractice.frontmatter.title} |
||||||
|
description={bestPractice.frontmatter.description} |
||||||
|
/> |
||||||
|
)) |
||||||
|
} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</BaseLayout> |
Loading…
Reference in new issue