diff --git a/.astro/settings.json b/.astro/settings.json
index 3c7258e30..b81828642 100644
--- a/.astro/settings.json
+++ b/.astro/settings.json
@@ -3,6 +3,6 @@
"enabled": false
},
"_variables": {
- "lastUpdateCheck": 1727087951727
+ "lastUpdateCheck": 1727095669945
}
}
\ No newline at end of file
diff --git a/package.json b/package.json
index ae63dca90..9a226056d 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ca43288d9..7f7d83e12 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -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
diff --git a/src/components/Changelog/ChangelogItem.astro b/src/components/Changelog/ChangelogItem.astro
new file mode 100644
index 000000000..3d793724a
--- /dev/null
+++ b/src/components/Changelog/ChangelogItem.astro
@@ -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',
+);
+---
+
+
+
+
+
+
+ {formattedDate}
+
+
+ {changelog.frontmatter.title}
+
+
+
+
+
diff --git a/src/components/MarkdownFile.astro b/src/components/MarkdownFile.astro
index 4d8bae22b..b12c5cd1a 100644
--- a/src/components/MarkdownFile.astro
+++ b/src/components/MarkdownFile.astro
@@ -1,5 +1,16 @@
+---
+interface Props {
+ class?: string;
+}
+
+const { class: className } = Astro.props;
+---
+
diff --git a/src/data/changelogs/leaderboard-page.md b/src/data/changelogs/leaderboard-page.md
new file mode 100644
index 000000000..d3fae968f
--- /dev/null
+++ b/src/data/changelogs/leaderboard-page.md
@@ -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.
\ No newline at end of file
diff --git a/src/data/changelogs/new-dashboard-page.md b/src/data/changelogs/new-dashboard-page.md
new file mode 100644
index 000000000..c0091731d
--- /dev/null
+++ b/src/data/changelogs/new-dashboard-page.md
@@ -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).
diff --git a/src/lib/changelog.ts b/src/lib/changelog.ts
new file mode 100644
index 000000000..038a03b6f
--- /dev/null
+++ b/src/lib/changelog.ts
@@ -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 & {
+ 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 {
+ // @ts-ignore
+ const changelogs = import.meta.glob(
+ '/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 {
+ const allChangelogs = await getAllChangelogs();
+
+ return allChangelogs.find((changelog) => changelog.id === id);
+}
diff --git a/src/pages/changelog.astro b/src/pages/changelog.astro
new file mode 100644
index 000000000..d7baac44a
--- /dev/null
+++ b/src/pages/changelog.astro
@@ -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();
+---
+
+
+
+
+
+
Changelog
+
Here is everything we have been shipping recently
+
+
+
+
+
+
+
+
+ {
+ allChangelogs.map((changelog) => (
+
+ ))
+ }
+
+
+
+