mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-07-31 22:40:19 +02:00
feat: implement changelog page (#7099)
* feat: implement leaderboard page * feat: sample changelog files * Update UI for changelog page * Make changelog page noindex --------- Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
This commit is contained in:
@@ -3,6 +3,6 @@
|
|||||||
"enabled": false
|
"enabled": false
|
||||||
},
|
},
|
||||||
"_variables": {
|
"_variables": {
|
||||||
"lastUpdateCheck": 1727087951727
|
"lastUpdateCheck": 1727095669945
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -50,6 +50,7 @@
|
|||||||
"jose": "^5.6.3",
|
"jose": "^5.6.3",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"lucide-react": "^0.419.0",
|
"lucide-react": "^0.419.0",
|
||||||
|
"luxon": "^3.5.0",
|
||||||
"nanoid": "^5.0.7",
|
"nanoid": "^5.0.7",
|
||||||
"nanostores": "^0.10.3",
|
"nanostores": "^0.10.3",
|
||||||
"node-html-parser": "^6.1.13",
|
"node-html-parser": "^6.1.13",
|
||||||
@@ -80,6 +81,7 @@
|
|||||||
"@tailwindcss/typography": "^0.5.13",
|
"@tailwindcss/typography": "^0.5.13",
|
||||||
"@types/dom-to-image": "^2.6.7",
|
"@types/dom-to-image": "^2.6.7",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/prismjs": "^1.26.4",
|
"@types/prismjs": "^1.26.4",
|
||||||
"@types/react-calendar-heatmap": "^1.6.7",
|
"@types/react-calendar-heatmap": "^1.6.7",
|
||||||
"@types/turndown": "^5.0.5",
|
"@types/turndown": "^5.0.5",
|
||||||
|
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@@ -71,6 +71,9 @@ importers:
|
|||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.419.0
|
specifier: ^0.419.0
|
||||||
version: 0.419.0(react@18.3.1)
|
version: 0.419.0(react@18.3.1)
|
||||||
|
luxon:
|
||||||
|
specifier: ^3.5.0
|
||||||
|
version: 3.5.0
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.0.7
|
specifier: ^5.0.7
|
||||||
version: 5.0.7
|
version: 5.0.7
|
||||||
@@ -156,6 +159,9 @@ importers:
|
|||||||
'@types/js-cookie':
|
'@types/js-cookie':
|
||||||
specifier: ^3.0.6
|
specifier: ^3.0.6
|
||||||
version: 3.0.6
|
version: 3.0.6
|
||||||
|
'@types/luxon':
|
||||||
|
specifier: ^3.4.2
|
||||||
|
version: 3.4.2
|
||||||
'@types/prismjs':
|
'@types/prismjs':
|
||||||
specifier: ^1.26.4
|
specifier: ^1.26.4
|
||||||
version: 1.26.4
|
version: 1.26.4
|
||||||
@@ -1246,6 +1252,9 @@ packages:
|
|||||||
'@types/js-cookie@3.0.6':
|
'@types/js-cookie@3.0.6':
|
||||||
resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
|
resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
|
||||||
|
|
||||||
|
'@types/luxon@3.4.2':
|
||||||
|
resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
|
||||||
|
|
||||||
'@types/mdast@4.0.4':
|
'@types/mdast@4.0.4':
|
||||||
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
||||||
|
|
||||||
@@ -2174,6 +2183,10 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
luxon@3.5.0:
|
||||||
|
resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
magic-string@0.30.11:
|
magic-string@0.30.11:
|
||||||
resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
|
resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
|
||||||
|
|
||||||
@@ -4238,6 +4251,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/js-cookie@3.0.6': {}
|
'@types/js-cookie@3.0.6': {}
|
||||||
|
|
||||||
|
'@types/luxon@3.4.2': {}
|
||||||
|
|
||||||
'@types/mdast@4.0.4':
|
'@types/mdast@4.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 3.0.3
|
'@types/unist': 3.0.3
|
||||||
@@ -5237,6 +5252,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
|
||||||
|
luxon@3.5.0: {}
|
||||||
|
|
||||||
magic-string@0.30.11:
|
magic-string@0.30.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
|
37
src/components/Changelog/ChangelogItem.astro
Normal file
37
src/components/Changelog/ChangelogItem.astro
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
import type { ChangelogFileType } from '../../lib/changelog';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import MarkdownFile from '../MarkdownFile.astro';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
changelog: ChangelogFileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { changelog } = Astro.props;
|
||||||
|
const { frontmatter } = changelog;
|
||||||
|
|
||||||
|
const formattedDate = DateTime.fromISO(frontmatter.date).toFormat(
|
||||||
|
'dd LLL, yyyy',
|
||||||
|
);
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class='relative'>
|
||||||
|
<span class='h-2 w-2 flex-shrink-0 rounded-full bg-gray-300 absolute top-2 -left-6'></span>
|
||||||
|
|
||||||
|
<div class='mb-3 flex items-center gap-2'>
|
||||||
|
<span class='flex-shrink-0 text-xs tracking-wide text-gray-400'>
|
||||||
|
{formattedDate}
|
||||||
|
</span>
|
||||||
|
<span class='truncate text-base font-medium'>
|
||||||
|
{changelog.frontmatter.title}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='rounded-xl border bg-white p-6'>
|
||||||
|
<div
|
||||||
|
class='prose prose-h2:text-lg prose-h2:font-medium prose-h2:mt-3 prose-sm prose-p:mb-0 prose-blockquote:font-normal prose-blockquote:text-gray-500 prose-ul:my-0 prose-img:mt-0 prose-img:rounded-lg [&>blockquote>p]:mt-0 prose-ul:bg-gray-100 prose-ul:rounded-lg prose-ul:px-4 prose-ul:py-4 prose-ul:pl-7 [&>ul>li]:my-0 [&>ul>li]:mb-1 [&>ul]:mt-3'
|
||||||
|
>
|
||||||
|
<changelog.Content />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -1,5 +1,16 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
class?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { class: className } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class='container prose-h2:text-balance prose-h3:text-balance prose-h4:text-balance prose-h5:text-balance prose prose-xl prose-h2:mb-3 prose-h2:mt-10 prose-h2:scroll-mt-5 prose-h2:text-3xl prose-h3:mt-2 prose-h3:scroll-mt-5 prose-h5:font-medium prose-blockquote:font-normal prose-code:bg-transparent prose-img:mt-1 prose-h2:sm:scroll-mt-10 prose-h3:sm:scroll-mt-10'
|
class:list={[
|
||||||
|
'container prose prose-xl prose-h2:mb-3 prose-h2:mt-10 prose-h2:scroll-mt-5 prose-h2:text-balance prose-h2:text-3xl prose-h3:mt-2 prose-h3:scroll-mt-5 prose-h3:text-balance prose-h4:text-balance prose-h5:text-balance prose-h5:font-medium prose-blockquote:font-normal prose-code:bg-transparent prose-img:mt-1 prose-h2:sm:scroll-mt-10 prose-h3:sm:scroll-mt-10',
|
||||||
|
className,
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
25
src/data/changelogs/leaderboard-page.md
Normal file
25
src/data/changelogs/leaderboard-page.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
title: 'New Dashboard, Leaderboards and Projects'
|
||||||
|
description: 'New leaderboard page showing the most active users'
|
||||||
|
seo:
|
||||||
|
title: 'Leaderboard Page - roadmap.sh'
|
||||||
|
description: ''
|
||||||
|
date: 2024-09-13
|
||||||
|
---
|
||||||
|
|
||||||
|
TL;DR: new dashboard, leaderboard page and projects page.
|
||||||
|
|
||||||
|
- New dashboard for logged-in users
|
||||||
|
- New leaderboard page
|
||||||
|
- Projects page listing all projects
|
||||||
|
- Ability to stop a started project
|
||||||
|
- Frontend and backend content improvements
|
||||||
|
- Bug fixes
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
We just launched a dedicated dashboard for logged-in users to showing progress, projects, bookmarks and more. You can still access the old homepage by visiting [this page](https://roadmap.sh/home).
|
||||||
|
|
||||||
|
We also launched a new [leaderboard page](/leaderboard) showing the most active users, users who completed most projects and more.
|
||||||
|
|
||||||
|
There is also a [new projects page](/projects) where you can see all the projects you have been working on. You can also now stop a started project.
|
12
src/data/changelogs/new-dashboard-page.md
Normal file
12
src/data/changelogs/new-dashboard-page.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: 'New Dashboard Page'
|
||||||
|
description: 'We have added a new dashboard page to help you track your progress'
|
||||||
|
seo:
|
||||||
|
title: 'New Dashboard Page - roadmap.sh'
|
||||||
|
description: 'We have added a new dashboard page to help you track your progress'
|
||||||
|
date: 2024-09-12
|
||||||
|
---
|
||||||
|
|
||||||
|
We have revamped the dashboard page for logged-in users. The new dashboard page will help you track your progress and see your overall progress in a single view. We have also added a new progress bar to help you visualize your progress.
|
||||||
|
|
||||||
|
If you want to access the guest homepage, you check check it out [here](/home).
|
69
src/lib/changelog.ts
Normal file
69
src/lib/changelog.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import type { MarkdownFileType } from './file';
|
||||||
|
|
||||||
|
export interface ChangelogFrontmatter {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
seo: {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChangelogFileType = MarkdownFileType<ChangelogFrontmatter> & {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates id from the given changelog file
|
||||||
|
* @param filePath Markdown file path
|
||||||
|
*
|
||||||
|
* @returns unique changelog identifier
|
||||||
|
*/
|
||||||
|
function changelogPathToId(filePath: string): string {
|
||||||
|
const fileName = filePath.split('/').pop() || '';
|
||||||
|
|
||||||
|
return fileName.replace('.md', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the changelogs sorted by the publishing date
|
||||||
|
* @returns Promisifed guide files
|
||||||
|
*/
|
||||||
|
export async function getAllChangelogs(): Promise<ChangelogFileType[]> {
|
||||||
|
// @ts-ignore
|
||||||
|
const changelogs = import.meta.glob<ChangelogFileType>(
|
||||||
|
'/src/data/changelogs/*.md',
|
||||||
|
{
|
||||||
|
eager: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const changelogFiles = Object.values(changelogs) as ChangelogFileType[];
|
||||||
|
const enrichedChangelogs: ChangelogFileType[] = changelogFiles.map(
|
||||||
|
(changelogFile) => ({
|
||||||
|
...changelogFile,
|
||||||
|
id: changelogPathToId(changelogFile.file),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return enrichedChangelogs.sort(
|
||||||
|
(a, b) =>
|
||||||
|
new Date(b.frontmatter.date).valueOf() -
|
||||||
|
new Date(a.frontmatter.date).valueOf(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the changelog by the given id
|
||||||
|
* @param id Changelog identifier
|
||||||
|
* @returns Promisified changelog file
|
||||||
|
*/
|
||||||
|
|
||||||
|
export async function getChangelogById(
|
||||||
|
id: string,
|
||||||
|
): Promise<ChangelogFileType | undefined> {
|
||||||
|
const allChangelogs = await getAllChangelogs();
|
||||||
|
|
||||||
|
return allChangelogs.find((changelog) => changelog.id === id);
|
||||||
|
}
|
39
src/pages/changelog.astro
Normal file
39
src/pages/changelog.astro
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
import SimplePageHeader from '../components/SimplePageHeader.astro';
|
||||||
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||||
|
import { getAllChangelogs } from '../lib/changelog';
|
||||||
|
import ChangelogItem from '../components/Changelog/ChangelogItem.astro';
|
||||||
|
|
||||||
|
const allChangelogs = await getAllChangelogs();
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout
|
||||||
|
title='Changelogs'
|
||||||
|
description='Changelogs for the updates and changes in the website'
|
||||||
|
permalink='/changelogs'
|
||||||
|
noIndex={true}
|
||||||
|
>
|
||||||
|
<div class='bg-gray-100'>
|
||||||
|
<div class='rounded-lg border-b bg-white text-left'>
|
||||||
|
<div class='mx-auto max-w-[500px] pt-12 pb-10 text-center'>
|
||||||
|
<h1 class='mb-3 text-4xl font-semibold'>Changelog</h1>
|
||||||
|
<p>Here is everything we have been shipping recently</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='relative mx-auto max-w-[500px] pb-8 pt-4'>
|
||||||
|
<div class='space-y-6'>
|
||||||
|
<div
|
||||||
|
class='absolute inset-y-0 -left-5 w-px -translate-x-[0.5px] bg-gray-300'
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
allChangelogs.map((changelog) => (
|
||||||
|
<ChangelogItem changelog={changelog} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseLayout>
|
Reference in New Issue
Block a user