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