mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-01-16 21:58:30 +01: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:
parent
3166a02f23
commit
9948e89b84
@ -3,6 +3,6 @@
|
||||
"enabled": false
|
||||
},
|
||||
"_variables": {
|
||||
"lastUpdateCheck": 1727087951727
|
||||
"lastUpdateCheck": 1727095669945
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@
|
||||
"jose": "^5.6.3",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lucide-react": "^0.419.0",
|
||||
"luxon": "^3.5.0",
|
||||
"nanoid": "^5.0.7",
|
||||
"nanostores": "^0.10.3",
|
||||
"node-html-parser": "^6.1.13",
|
||||
@ -80,6 +81,7 @@
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"@types/dom-to-image": "^2.6.7",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/prismjs": "^1.26.4",
|
||||
"@types/react-calendar-heatmap": "^1.6.7",
|
||||
"@types/turndown": "^5.0.5",
|
||||
|
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@ -71,6 +71,9 @@ importers:
|
||||
lucide-react:
|
||||
specifier: ^0.419.0
|
||||
version: 0.419.0(react@18.3.1)
|
||||
luxon:
|
||||
specifier: ^3.5.0
|
||||
version: 3.5.0
|
||||
nanoid:
|
||||
specifier: ^5.0.7
|
||||
version: 5.0.7
|
||||
@ -156,6 +159,9 @@ importers:
|
||||
'@types/js-cookie':
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
'@types/luxon':
|
||||
specifier: ^3.4.2
|
||||
version: 3.4.2
|
||||
'@types/prismjs':
|
||||
specifier: ^1.26.4
|
||||
version: 1.26.4
|
||||
@ -1246,6 +1252,9 @@ packages:
|
||||
'@types/js-cookie@3.0.6':
|
||||
resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
|
||||
|
||||
'@types/luxon@3.4.2':
|
||||
resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
||||
|
||||
@ -2174,6 +2183,10 @@ packages:
|
||||
peerDependencies:
|
||||
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:
|
||||
resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
|
||||
|
||||
@ -4238,6 +4251,8 @@ snapshots:
|
||||
|
||||
'@types/js-cookie@3.0.6': {}
|
||||
|
||||
'@types/luxon@3.4.2': {}
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
@ -5237,6 +5252,8 @@ snapshots:
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
luxon@3.5.0: {}
|
||||
|
||||
magic-string@0.30.11:
|
||||
dependencies:
|
||||
'@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
|
||||
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 />
|
||||
</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
|
||||
|
||||
![Leaderboard Page](https://assets.roadmap.sh/guest/personal-dashboard.png)
|
||||
|
||||
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>
|
Loading…
x
Reference in New Issue
Block a user