From 53e87095ef7e0d4d0b27a358e4f88afb1a397a62 Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Mon, 23 Sep 2024 15:19:10 +0100 Subject: [PATCH] Update changelog page --- package-lock.json | 146 ++++++++++++++++++- package.json | 1 + pnpm-lock.yaml | 10 ++ src/components/Changelog/ChangelogItem.astro | 16 +- src/components/ChangelogImages.tsx | 108 ++++++++++++++ src/data/changelogs/leaderboard-page.md | 6 +- src/lib/changelog.ts | 1 + src/pages/changelog.astro | 16 +- 8 files changed, 282 insertions(+), 22 deletions(-) create mode 100644 src/components/ChangelogImages.tsx diff --git a/package-lock.json b/package-lock.json index e882195d3..64936bd10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,16 +29,18 @@ "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", "npm-check-updates": "^17.0.0", - "playwright": "^1.45.3", + "playwright": "^1.47.1", "prismjs": "^1.29.0", "react": "^18.3.1", "react-calendar-heatmap": "^1.9.0", "react-confetti": "^6.1.0", "react-dom": "^18.3.1", + "react-slick": "^0.30.2", "react-tooltip": "^5.27.1", "reactflow": "^11.11.4", "rehype-external-links": "^3.0.0", @@ -47,6 +49,7 @@ "satori": "^0.10.14", "satori-html": "^0.3.2", "sharp": "^0.33.4", + "slick-carousel": "^1.8.1", "slugify": "^1.6.6", "tailwind-merge": "^2.4.0", "tailwindcss": "^3.4.7", @@ -59,8 +62,10 @@ "@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/react-slick": "^0.23.13", "@types/turndown": "^5.0.5", "csv-parser": "^3.0.0", "gh-pages": "^6.1.1", @@ -1749,6 +1754,50 @@ "node": ">=18" } }, + "node_modules/@playwright/test/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/@playwright/test/node_modules/playwright": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.0.tgz", + "integrity": "sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==", + "dev": true, + "dependencies": { + "playwright-core": "1.46.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/@playwright/test/node_modules/playwright-core": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.0.tgz", + "integrity": "sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@reactflow/background": { "version": "11.3.14", "resolved": "https://registry.npmjs.org/@reactflow/background/-/background-11.3.14.tgz", @@ -2622,6 +2671,12 @@ "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", "dev": true }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==", + "dev": true + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -2698,6 +2753,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-slick": { + "version": "0.23.13", + "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.13.tgz", + "integrity": "sha512-bNZfDhe/L8t5OQzIyhrRhBr/61pfBcWaYJoq6UDqFtv5LMwfg4NsVDD2J8N01JqdAdxLjOt66OZEp6PX+dGs/A==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/sax": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", @@ -3931,6 +3995,11 @@ "iconv-lite": "^0.6.2" } }, + "node_modules/enquire.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz", + "integrity": "sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw==" + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -4953,6 +5022,12 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "peer": true + }, "node_modules/js-cookie": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", @@ -4988,6 +5063,14 @@ "node": ">=4" } }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "dependencies": { + "string-convert": "^0.2.0" + } + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -5114,6 +5197,11 @@ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "dev": true }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -5199,6 +5287,14 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -6656,11 +6752,11 @@ } }, "node_modules/playwright": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.0.tgz", - "integrity": "sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==", + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz", + "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==", "dependencies": { - "playwright-core": "1.46.0" + "playwright-core": "1.47.2" }, "bin": { "playwright": "cli.js" @@ -6673,9 +6769,9 @@ } }, "node_modules/playwright-core": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.0.tgz", - "integrity": "sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==", + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz", + "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==", "bin": { "playwright-core": "cli.js" }, @@ -7125,6 +7221,22 @@ "node": ">=0.10.0" } }, + "node_modules/react-slick": { + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.30.2.tgz", + "integrity": "sha512-XvQJi7mRHuiU3b9irsqS9SGIgftIfdV5/tNcURTb5LdIokRA5kIIx3l4rlq2XYHfxcSntXapoRg/GxaVOM1yfg==", + "dependencies": { + "classnames": "^2.2.5", + "enquire.js": "^2.1.6", + "json2mq": "^0.2.0", + "lodash.debounce": "^4.0.8", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-tooltip": { "version": "5.27.1", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.27.1.tgz", @@ -7329,6 +7441,11 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -7771,6 +7888,14 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" }, + "node_modules/slick-carousel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/slick-carousel/-/slick-carousel-1.8.1.tgz", + "integrity": "sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA==", + "peerDependencies": { + "jquery": ">=1.8.0" + } + }, "node_modules/slugify": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", @@ -7820,6 +7945,11 @@ "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==" }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" + }, "node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", diff --git a/package.json b/package.json index 9a226056d..3c6f56cf9 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "@types/luxon": "^3.4.2", "@types/prismjs": "^1.26.4", "@types/react-calendar-heatmap": "^1.6.7", + "@types/react-slick": "^0.23.13", "@types/turndown": "^5.0.5", "csv-parser": "^3.0.0", "gh-pages": "^6.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f7d83e12..bd67d3253 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -168,6 +168,9 @@ importers: '@types/react-calendar-heatmap': specifier: ^1.6.7 version: 1.6.7 + '@types/react-slick': + specifier: ^0.23.13 + version: 0.23.13 '@types/turndown': specifier: ^5.0.5 version: 5.0.5 @@ -1285,6 +1288,9 @@ packages: '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + '@types/react-slick@0.23.13': + resolution: {integrity: sha512-bNZfDhe/L8t5OQzIyhrRhBr/61pfBcWaYJoq6UDqFtv5LMwfg4NsVDD2J8N01JqdAdxLjOt66OZEp6PX+dGs/A==} + '@types/react@18.3.8': resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} @@ -4286,6 +4292,10 @@ snapshots: dependencies: '@types/react': 18.3.8 + '@types/react-slick@0.23.13': + dependencies: + '@types/react': 18.3.8 + '@types/react@18.3.8': dependencies: '@types/prop-types': 15.7.13 diff --git a/src/components/Changelog/ChangelogItem.astro b/src/components/Changelog/ChangelogItem.astro index 3d793724a..ca008a2ca 100644 --- a/src/components/Changelog/ChangelogItem.astro +++ b/src/components/Changelog/ChangelogItem.astro @@ -1,7 +1,7 @@ --- -import type { ChangelogFileType } from '../../lib/changelog'; import { DateTime } from 'luxon'; -import MarkdownFile from '../MarkdownFile.astro'; +import type { ChangelogFileType } from '../../lib/changelog'; +import ChangelogImages from '../ChangelogImages'; interface Props { changelog: ChangelogFileType; @@ -16,7 +16,9 @@ const formattedDate = DateTime.fromISO(frontmatter.date).toFormat( ---
- +
@@ -28,8 +30,14 @@ const formattedDate = DateTime.fromISO(frontmatter.date).toFormat(
+ {frontmatter.images && ( +
+ +
+ )} +
diff --git a/src/components/ChangelogImages.tsx b/src/components/ChangelogImages.tsx new file mode 100644 index 000000000..359efe313 --- /dev/null +++ b/src/components/ChangelogImages.tsx @@ -0,0 +1,108 @@ +import { ChevronLeft, ChevronRight, MoveRight } from 'lucide-react'; +import React, { useState, useEffect, useCallback } from 'react'; + +interface ChangelogImagesProps { + images: { [key: string]: string }; +} + +const ChangelogImages: React.FC = ({ images }) => { + const [enlargedImage, setEnlargedImage] = useState(null); + const imageArray = Object.entries(images); + + const handleImageClick = (src: string) => { + setEnlargedImage(src); + }; + + const handleCloseEnlarged = () => { + setEnlargedImage(null); + }; + + const handleNavigation = useCallback( + (direction: 'prev' | 'next') => { + if (!enlargedImage) return; + const currentIndex = imageArray.findIndex( + ([_, src]) => src === enlargedImage, + ); + let newIndex; + if (direction === 'prev') { + newIndex = currentIndex > 0 ? currentIndex - 1 : imageArray.length - 1; + } else { + newIndex = currentIndex < imageArray.length - 1 ? currentIndex + 1 : 0; + } + setEnlargedImage(imageArray[newIndex][1]); + }, + [enlargedImage, imageArray], + ); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + handleCloseEnlarged(); + } else if (event.key === 'ArrowLeft') { + handleNavigation('prev'); + } else if (event.key === 'ArrowRight') { + handleNavigation('next'); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [handleNavigation]); + + return ( + <> +
+ {imageArray.map(([title, src]) => ( +
handleImageClick(src)} + > + {title} + + +
+ {title} +
+
+ ))} +
+ {enlargedImage && ( +
+ Enlarged view + + +
+ )} + + ); +}; + +export default ChangelogImages; diff --git a/src/data/changelogs/leaderboard-page.md b/src/data/changelogs/leaderboard-page.md index d3fae968f..4909322fb 100644 --- a/src/data/changelogs/leaderboard-page.md +++ b/src/data/changelogs/leaderboard-page.md @@ -1,6 +1,10 @@ --- title: 'New Dashboard, Leaderboards and Projects' description: 'New leaderboard page showing the most active users' +images: + "Personal Dashboard": "https://assets.roadmap.sh/guest/personal-dashboard.png" + "Projects Page": "https://assets.roadmap.sh/guest/projects-page.png" + "Leaderboard": "https://assets.roadmap.sh/guest/leaderboard.png" seo: title: 'Leaderboard Page - roadmap.sh' description: '' @@ -16,8 +20,6 @@ TL;DR: new dashboard, leaderboard page and projects page. - 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. diff --git a/src/lib/changelog.ts b/src/lib/changelog.ts index 038a03b6f..bcb39a3f9 100644 --- a/src/lib/changelog.ts +++ b/src/lib/changelog.ts @@ -3,6 +3,7 @@ import type { MarkdownFileType } from './file'; export interface ChangelogFrontmatter { title: string; description: string; + images: Record; seo: { title: string; description: string; diff --git a/src/pages/changelog.astro b/src/pages/changelog.astro index d7baac44a..7fa10baec 100644 --- a/src/pages/changelog.astro +++ b/src/pages/changelog.astro @@ -9,22 +9,22 @@ const allChangelogs = await getAllChangelogs(); -
-
-
-

Changelog

-

Here is everything we have been shipping recently

+
+
+
+

Changelog

+

We are constantly improving and updating roadmap.sh

-
+