mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2026-03-12 17:51:53 +08:00
Update changelog page
This commit is contained in:
146
package-lock.json
generated
146
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -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
|
||||
|
||||
@@ -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(
|
||||
---
|
||||
|
||||
<div class='relative'>
|
||||
<span class='h-2 w-2 flex-shrink-0 rounded-full bg-gray-300 absolute top-2 -left-6'></span>
|
||||
<span
|
||||
class='absolute -left-6 top-2 h-2 w-2 flex-shrink-0 rounded-full bg-gray-300'
|
||||
></span>
|
||||
|
||||
<div class='mb-3 flex items-center gap-2'>
|
||||
<span class='flex-shrink-0 text-xs tracking-wide text-gray-400'>
|
||||
@@ -28,8 +30,14 @@ const formattedDate = DateTime.fromISO(frontmatter.date).toFormat(
|
||||
</div>
|
||||
|
||||
<div class='rounded-xl border bg-white p-6'>
|
||||
{frontmatter.images && (
|
||||
<div class='mb-5 -mx-6'>
|
||||
<ChangelogImages images={frontmatter.images} client:load />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<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'
|
||||
class='prose prose-sm prose-h2:mt-3 prose-h2:text-lg prose-h2:font-medium prose-p:mb-0 prose-blockquote:font-normal prose-blockquote:text-gray-500 prose-ul:my-0 prose-ul:rounded-lg prose-ul:bg-gray-100 prose-ul:px-4 prose-ul:py-4 prose-ul:pl-7 prose-img:mt-0 prose-img:rounded-lg [&>blockquote>p]:mt-0 [&>ul>li]:my-0 [&>ul>li]:mb-1 [&>ul]:mt-3'
|
||||
>
|
||||
<changelog.Content />
|
||||
</div>
|
||||
|
||||
108
src/components/ChangelogImages.tsx
Normal file
108
src/components/ChangelogImages.tsx
Normal file
@@ -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<ChangelogImagesProps> = ({ images }) => {
|
||||
const [enlargedImage, setEnlargedImage] = useState<string | null>(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 (
|
||||
<>
|
||||
<div className="flex gap-3 px-6 pb-1">
|
||||
{imageArray.map(([title, src]) => (
|
||||
<div
|
||||
key={title}
|
||||
className="group relative cursor-pointer overflow-hidden rounded-lg transition hover:scale-105"
|
||||
onClick={() => handleImageClick(src)}
|
||||
>
|
||||
<img
|
||||
src={src}
|
||||
alt={title}
|
||||
className="h-[120px] w-full object-cover object-left-top"
|
||||
/>
|
||||
<span className="absolute group-hover:opacity-0 inset-0 bg-gradient-to-b from-transparent to-black/40" />
|
||||
|
||||
<div className="absolute font-medium inset-x-0 top-full group-hover:inset-y-0 flex items-center justify-center px-2 text-center text-xs bg-black/50 text-white py-0.5 opacity-0 group-hover:opacity-100">
|
||||
<span className='bg-black py-0.5 rounded px-1'>{title}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{enlargedImage && (
|
||||
<div
|
||||
className="fixed inset-0 z-[999] flex items-center justify-center bg-black bg-opacity-75"
|
||||
onClick={handleCloseEnlarged}
|
||||
>
|
||||
<img
|
||||
src={enlargedImage}
|
||||
alt="Enlarged view"
|
||||
className="max-h-[90%] max-w-[90%] rounded-xl object-contain"
|
||||
/>
|
||||
<button
|
||||
className="absolute left-4 top-1/2 -translate-y-1/2 transform rounded-full bg-white hover:bg-opacity-100 bg-opacity-50 p-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleNavigation('prev');
|
||||
}}
|
||||
>
|
||||
<ChevronLeft size={24} />
|
||||
</button>
|
||||
<button
|
||||
className="absolute right-4 top-1/2 -translate-y-1/2 transform rounded-full bg-white hover:bg-opacity-100 bg-opacity-50 p-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleNavigation('next');
|
||||
}}
|
||||
>
|
||||
<ChevronRight size={24} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangelogImages;
|
||||
@@ -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
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { MarkdownFileType } from './file';
|
||||
export interface ChangelogFrontmatter {
|
||||
title: string;
|
||||
description: string;
|
||||
images: Record<string, string>;
|
||||
seo: {
|
||||
title: string;
|
||||
description: string;
|
||||
|
||||
@@ -9,22 +9,22 @@ const allChangelogs = await getAllChangelogs();
|
||||
|
||||
<BaseLayout
|
||||
title='Changelogs'
|
||||
description='Changelogs for the updates and changes in the website'
|
||||
description='Changelogs for the updates and changes to roadmap.sh'
|
||||
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 class='bg-gray-100 px-4'>
|
||||
<div class='border-b bg-white text-left -mx-4'>
|
||||
<div class='mx-auto max-w-[500px] py-5 sm:pb-10 sm:pt-12 text-left px-4 sm:text-center'>
|
||||
<h1 class='mb-0.5 sm:mb-3 text-2xl sm:text-4xl font-semibold'>Changelog</h1>
|
||||
<p>We are constantly improving and updating roadmap.sh</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='relative mx-auto max-w-[500px] pb-8 pt-4'>
|
||||
<div class='relative mx-auto max-w-[600px] 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'
|
||||
class='absolute sm:block hidden inset-y-0 -left-5 w-px -translate-x-[0.5px] bg-gray-300'
|
||||
>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user