diff --git a/.gitignore b/.gitignore
index 83c2988d..c10e7420 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,6 @@ pnpm-error.log*
# cursor
.cursorrules
.cursor
+
+# playwright mcp
+.playwright-mcp/
diff --git a/content/rounds/agr26.mdx b/content/rounds/agr26.mdx
new file mode 100644
index 00000000..7b8eb2c7
--- /dev/null
+++ b/content/rounds/agr26.mdx
@@ -0,0 +1,40 @@
+---
+slug: 'agr26'
+name: 'Academic Grants Round 2026'
+description: 'Supporting Ethereum academic research with targeted funding for researchers and institutions.'
+status: 'active'
+tag: 'AGR26'
+heroImage: '/images/academic-grants-25-hero.jpeg'
+colorBrand: 'academicGrants2026Hero'
+startDate: '2026-01-20'
+endDate: '2026-03-24'
+---
+
+## About
+
+The Academic Grants Round 2026 (AGR26) is designed to support academic research that advances the Ethereum ecosystem. We are looking for researchers and institutions working on projects that contribute to Ethereum's technical, economic, or social foundations.
+
+### What We're Looking For
+
+- Research that advances Ethereum's core protocol
+- Studies on cryptographic primitives and security
+- Economic analysis of Ethereum's mechanisms
+- Research on scalability solutions
+- Investigations into decentralized governance
+
+### Eligibility
+
+- Academic researchers at accredited institutions
+- Independent researchers with demonstrated expertise
+- Research teams working on Ethereum-related topics
+
+### Timeline
+
+- **Applications Open:** January 20, 2026
+- **Applications Close:** March 24, 2026
+- **Review Period:** March - April 2026
+- **Announcements:** May 2026
+
+### Support
+
+For questions about this grant round, please contact [academic-grants@ethereum.org](mailto:academic-grants@ethereum.org).
diff --git a/package.json b/package.json
index 2065e562..22dfc9ed 100644
--- a/package.json
+++ b/package.json
@@ -32,11 +32,14 @@
"focus-visible": "^5.2.0",
"formidable": "^2.0.1",
"framer-motion": "^11.0.5",
+ "github-slugger": "^2.0.0",
"google-spreadsheet": "^3.2.0",
+ "gray-matter": "^4.0.3",
"jsforce": "^1.11.0",
"jsonwebtoken": "^9.0.2",
"lucide-react": "^0.546.0",
"next": "^14.2.35",
+ "next-mdx-remote": "^5.0.0",
"next-sitemap": "^2.5.7",
"papaparse": "^5.3.1",
"react": "^18.3.1",
@@ -46,6 +49,7 @@
"react-intersection-observer": "^8.33.1",
"react-markdown": "^8.0.0",
"redaxios": "^0.4.1",
+ "rehype-slug": "^6.0.0",
"sharp": "^0.33.2"
},
"devDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e15c2fd9..af114464 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -56,9 +56,15 @@ importers:
framer-motion:
specifier: ^11.0.5
version: 11.18.2(@emotion/is-prop-valid@1.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ github-slugger:
+ specifier: ^2.0.0
+ version: 2.0.0
google-spreadsheet:
specifier: ^3.2.0
version: 3.3.0
+ gray-matter:
+ specifier: ^4.0.3
+ version: 4.0.3
jsforce:
specifier: ^1.11.0
version: 1.11.1
@@ -71,6 +77,9 @@ importers:
next:
specifier: ^14.2.35
version: 14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ next-mdx-remote:
+ specifier: ^5.0.0
+ version: 5.0.0(@types/react@18.3.23)(react@18.3.1)
next-sitemap:
specifier: ^2.5.7
version: 2.5.28(next@14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
@@ -98,6 +107,9 @@ importers:
redaxios:
specifier: ^0.4.1
version: 0.4.1
+ rehype-slug:
+ specifier: ^6.0.0
+ version: 6.0.0
sharp:
specifier: ^0.33.2
version: 0.33.5
@@ -170,7 +182,7 @@ importers:
version: 13.15.22
vitest:
specifier: ^3.0.0
- version: 3.2.4(@types/debug@4.1.12)(@types/node@17.0.0)(tsx@4.21.0)
+ version: 3.2.4(@types/debug@4.1.12)(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2)
zod:
specifier: ^3.22.3
version: 3.25.76
@@ -781,6 +793,15 @@ packages:
resolution: {integrity: sha512-Cgz0xPb+1DUjmrl5whAsmqfAChBko+Wf4/PLQE4RvwfPlcq2agfHr1QFiXEhZ8e+GQwQ3hZQn9iLGXwIXwxUCg==}
engines: {node: '>=10.0.0'}
+ '@mdx-js/mdx@3.1.1':
+ resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==}
+
+ '@mdx-js/react@3.1.1':
+ resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==}
+ peerDependencies:
+ '@types/react': '>=16'
+ react: '>=16'
+
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
@@ -1028,6 +1049,9 @@ packages:
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+ '@types/estree-jsx@1.0.5':
+ resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
+
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -1040,6 +1064,9 @@ packages:
'@types/hast@2.3.10':
resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==}
+ '@types/hast@3.0.4':
+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+
'@types/jsforce@1.11.5':
resolution: {integrity: sha512-68uPAse+nDBDnh421L9ngd7jn11hST+Gz2CJMz5l+M4UVD2fYJsgdZQReZf7bTZQsIUdnr0sAp71ihLxAusZZA==}
@@ -1067,6 +1094,12 @@ packages:
'@types/mdast@3.0.15':
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
+ '@types/mdast@4.0.4':
+ resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
+
+ '@types/mdx@2.0.13':
+ resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==}
+
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
@@ -1107,6 +1140,9 @@ packages:
'@types/unist@2.0.11':
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
+ '@types/unist@3.0.3':
+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+
'@types/validator@13.15.2':
resolution: {integrity: sha512-y7pa/oEJJ4iGYBxOpfAKn5b9+xuihvzDVnC/OSvlVnGxVg0pOqmjiMafiJ1KVNQEaPZf9HsEp5icEwGg8uIe5Q==}
@@ -1341,6 +1377,9 @@ packages:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
+ argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -1409,6 +1448,10 @@ packages:
ast-types-flow@0.0.8:
resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
+ astring@1.9.0:
+ resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
+ hasBin: true
+
async-function@1.0.0:
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
engines: {node: '>= 0.4'}
@@ -1507,6 +1550,9 @@ packages:
caseless@0.12.0:
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
+ ccount@2.0.1:
+ resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+
chai@5.3.3:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
@@ -1528,9 +1574,18 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
+ character-entities-html4@2.1.0:
+ resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
+
+ character-entities-legacy@3.0.0:
+ resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
+
character-entities@2.0.2:
resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
+ character-reference-invalid@2.0.1:
+ resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
+
check-error@2.1.3:
resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
engines: {node: '>= 16'}
@@ -1546,6 +1601,9 @@ packages:
engines: {node: '>=0.8.0'}
hasBin: true
+ collapse-white-space@2.1.0:
+ resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
+
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -1709,6 +1767,9 @@ packages:
detect-node-es@1.1.0:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
+ devlop@1.1.0:
+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+
dezalgo@1.0.4:
resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
@@ -1796,6 +1857,12 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
+ esast-util-from-estree@2.0.0:
+ resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
+
+ esast-util-from-js@2.0.1:
+ resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==}
+
esbuild@0.27.2:
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
engines: {node: '>=18'}
@@ -1907,6 +1974,11 @@ packages:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+
esquery@1.6.0:
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
engines: {node: '>=0.10'}
@@ -1923,6 +1995,24 @@ packages:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
+ estree-util-attach-comments@3.0.0:
+ resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==}
+
+ estree-util-build-jsx@3.0.1:
+ resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==}
+
+ estree-util-is-identifier-name@3.0.0:
+ resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==}
+
+ estree-util-scope@1.0.0:
+ resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==}
+
+ estree-util-to-js@2.0.0:
+ resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==}
+
+ estree-util-visit@2.0.0:
+ resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==}
+
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
@@ -1938,6 +2028,10 @@ packages:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
+ extend-shallow@2.0.1:
+ resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
+ engines: {node: '>=0.10.0'}
+
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
@@ -2121,6 +2215,9 @@ packages:
getpass@0.1.7:
resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
+ github-slugger@2.0.0:
+ resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
+
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -2174,6 +2271,10 @@ packages:
graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ gray-matter@4.0.3:
+ resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
+ engines: {node: '>=6.0'}
+
gtoken@5.3.2:
resolution: {integrity: sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==}
engines: {node: '>=10'}
@@ -2214,9 +2315,24 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ hast-util-heading-rank@3.0.0:
+ resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==}
+
+ hast-util-to-estree@3.1.3:
+ resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==}
+
+ hast-util-to-jsx-runtime@2.3.6:
+ resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
+
+ hast-util-to-string@3.0.1:
+ resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==}
+
hast-util-whitespace@2.0.1:
resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==}
+ hast-util-whitespace@3.0.0:
+ resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
+
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
@@ -2253,10 +2369,19 @@ packages:
inline-style-parser@0.1.1:
resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==}
+ inline-style-parser@0.2.7:
+ resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
+
internal-slot@1.1.0:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
+ is-alphabetical@2.0.1:
+ resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==}
+
+ is-alphanumerical@2.0.1:
+ resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
+
is-array-buffer@3.0.5:
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
engines: {node: '>= 0.4'}
@@ -2302,6 +2427,13 @@ packages:
resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
engines: {node: '>= 0.4'}
+ is-decimal@2.0.1:
+ resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
+
+ is-extendable@0.1.1:
+ resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
+ engines: {node: '>=0.10.0'}
+
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -2322,6 +2454,9 @@ packages:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
+ is-hexadecimal@2.0.1:
+ resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==}
+
is-map@2.0.3:
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
engines: {node: '>= 0.4'}
@@ -2419,6 +2554,10 @@ packages:
js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+ js-yaml@3.14.2:
+ resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
+ hasBin: true
+
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@@ -2491,6 +2630,10 @@ packages:
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ kind-of@6.0.3:
+ resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+ engines: {node: '>=0.10.0'}
+
kleur@4.1.5:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
@@ -2547,6 +2690,9 @@ packages:
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ longest-streak@3.1.0:
+ resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
+
loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@@ -2569,6 +2715,10 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+ markdown-extensions@2.0.0:
+ resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
+ engines: {node: '>=16'}
+
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@@ -2579,12 +2729,39 @@ packages:
mdast-util-from-markdown@1.3.1:
resolution: {integrity: sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==}
+ mdast-util-from-markdown@2.0.2:
+ resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==}
+
+ mdast-util-mdx-expression@2.0.1:
+ resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
+
+ mdast-util-mdx-jsx@3.2.0:
+ resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==}
+
+ mdast-util-mdx@3.0.0:
+ resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==}
+
+ mdast-util-mdxjs-esm@2.0.1:
+ resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==}
+
+ mdast-util-phrasing@4.1.0:
+ resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
+
mdast-util-to-hast@12.3.0:
resolution: {integrity: sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==}
+ mdast-util-to-hast@13.2.1:
+ resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==}
+
+ mdast-util-to-markdown@2.1.2:
+ resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
+
mdast-util-to-string@3.2.0:
resolution: {integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==}
+ mdast-util-to-string@4.0.0:
+ resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+
memoize-one@6.0.0:
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
@@ -2599,66 +2776,150 @@ packages:
micromark-core-commonmark@1.1.0:
resolution: {integrity: sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==}
+ micromark-core-commonmark@2.0.3:
+ resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
+
+ micromark-extension-mdx-expression@3.0.1:
+ resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==}
+
+ micromark-extension-mdx-jsx@3.0.2:
+ resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==}
+
+ micromark-extension-mdx-md@2.0.0:
+ resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==}
+
+ micromark-extension-mdxjs-esm@3.0.0:
+ resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==}
+
+ micromark-extension-mdxjs@3.0.0:
+ resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==}
+
micromark-factory-destination@1.1.0:
resolution: {integrity: sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==}
+ micromark-factory-destination@2.0.1:
+ resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
+
micromark-factory-label@1.1.0:
resolution: {integrity: sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==}
+ micromark-factory-label@2.0.1:
+ resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==}
+
+ micromark-factory-mdx-expression@2.0.3:
+ resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==}
+
micromark-factory-space@1.1.0:
resolution: {integrity: sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==}
+ micromark-factory-space@2.0.1:
+ resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==}
+
micromark-factory-title@1.1.0:
resolution: {integrity: sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==}
+ micromark-factory-title@2.0.1:
+ resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==}
+
micromark-factory-whitespace@1.1.0:
resolution: {integrity: sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==}
+ micromark-factory-whitespace@2.0.1:
+ resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==}
+
micromark-util-character@1.2.0:
resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==}
+ micromark-util-character@2.1.1:
+ resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
+
micromark-util-chunked@1.1.0:
resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==}
+ micromark-util-chunked@2.0.1:
+ resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==}
+
micromark-util-classify-character@1.1.0:
resolution: {integrity: sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==}
+ micromark-util-classify-character@2.0.1:
+ resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==}
+
micromark-util-combine-extensions@1.1.0:
resolution: {integrity: sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==}
+ micromark-util-combine-extensions@2.0.1:
+ resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==}
+
micromark-util-decode-numeric-character-reference@1.1.0:
resolution: {integrity: sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==}
+ micromark-util-decode-numeric-character-reference@2.0.2:
+ resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==}
+
micromark-util-decode-string@1.1.0:
resolution: {integrity: sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==}
+ micromark-util-decode-string@2.0.1:
+ resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==}
+
micromark-util-encode@1.1.0:
resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==}
+ micromark-util-encode@2.0.1:
+ resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
+
+ micromark-util-events-to-acorn@2.0.3:
+ resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==}
+
micromark-util-html-tag-name@1.2.0:
resolution: {integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==}
+ micromark-util-html-tag-name@2.0.1:
+ resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==}
+
micromark-util-normalize-identifier@1.1.0:
resolution: {integrity: sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==}
+ micromark-util-normalize-identifier@2.0.1:
+ resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==}
+
micromark-util-resolve-all@1.1.0:
resolution: {integrity: sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==}
+ micromark-util-resolve-all@2.0.1:
+ resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==}
+
micromark-util-sanitize-uri@1.2.0:
resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==}
+ micromark-util-sanitize-uri@2.0.1:
+ resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
+
micromark-util-subtokenize@1.1.0:
resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==}
+ micromark-util-subtokenize@2.1.0:
+ resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==}
+
micromark-util-symbol@1.1.0:
resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==}
+ micromark-util-symbol@2.0.1:
+ resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
+
micromark-util-types@1.1.0:
resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==}
+ micromark-util-types@2.0.2:
+ resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
+
micromark@3.2.0:
resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==}
+ micromark@4.0.2:
+ resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
+
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
@@ -2722,6 +2983,12 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ next-mdx-remote@5.0.0:
+ resolution: {integrity: sha512-RNNbqRpK9/dcIFZs/esQhuLA8jANqlH694yqoDBK8hkVdJUndzzGmnPHa2nyi90N4Z9VmzuSWNRpr5ItT3M7xQ==}
+ engines: {node: '>=14', npm: '>=7'}
+ peerDependencies:
+ react: '>=16'
+
next-sitemap@2.5.28:
resolution: {integrity: sha512-rDMTa7nLE0ikYnu8JDCrwQufIRm4b4Sg8BK11DGdDAmYpXmcmw4Qvm+oVBR8gUL97E6i2ihTM+cRx8mgENDACA==}
engines: {node: '>=14.18'}
@@ -2825,6 +3092,9 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parse-entities@4.0.2:
+ resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
+
parse-json@5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
@@ -2910,6 +3180,9 @@ packages:
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
+ property-information@7.1.0:
+ resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
+
psl@1.15.0:
resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
@@ -3031,6 +3304,20 @@ packages:
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
+ recma-build-jsx@1.0.0:
+ resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==}
+
+ recma-jsx@1.0.1:
+ resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ recma-parse@1.0.0:
+ resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==}
+
+ recma-stringify@1.0.0:
+ resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==}
+
redaxios@0.4.1:
resolution: {integrity: sha512-+Jhh1j8/H0KBro+Hih/MrDEJ1PICaU10JA6iu5b3+uvgRI+5n2M7qpMNXq7eC/0fspP0tTq49ONXlGWFdRoNLg==}
@@ -3042,12 +3329,27 @@ packages:
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
engines: {node: '>= 0.4'}
+ rehype-recma@1.0.0:
+ resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==}
+
+ rehype-slug@6.0.0:
+ resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==}
+
+ remark-mdx@3.1.1:
+ resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==}
+
remark-parse@10.0.2:
resolution: {integrity: sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==}
+ remark-parse@11.0.0:
+ resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
+
remark-rehype@10.1.0:
resolution: {integrity: sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==}
+ remark-rehype@11.1.2:
+ resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
+
request@2.88.2:
resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
engines: {node: '>= 6'}
@@ -3122,6 +3424,10 @@ packages:
scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
+ section-matter@1.0.0:
+ resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
+ engines: {node: '>=4'}
+
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -3202,9 +3508,16 @@ packages:
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
engines: {node: '>=0.10.0'}
+ source-map@0.7.6:
+ resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
+ engines: {node: '>= 12'}
+
space-separated-tokens@2.0.2:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
+ sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+
sshpk@1.18.0:
resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==}
engines: {node: '>=0.10.0'}
@@ -3261,6 +3574,9 @@ packages:
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+ stringify-entities@4.0.4:
+ resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
+
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
@@ -3269,6 +3585,10 @@ packages:
resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
engines: {node: '>=12'}
+ strip-bom-string@1.0.0:
+ resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
+ engines: {node: '>=0.10.0'}
+
strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
@@ -3280,9 +3600,15 @@ packages:
strip-literal@3.1.0:
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
+ style-to-js@1.1.21:
+ resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==}
+
style-to-object@0.4.4:
resolution: {integrity: sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==}
+ style-to-object@1.0.14:
+ resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==}
+
styled-jsx@5.1.1:
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==}
engines: {node: '>= 12.0.0'}
@@ -3436,24 +3762,48 @@ packages:
unified@10.1.2:
resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==}
+ unified@11.0.5:
+ resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
+
unist-util-generated@2.0.1:
resolution: {integrity: sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==}
unist-util-is@5.2.1:
resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==}
+ unist-util-is@6.0.1:
+ resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
+
+ unist-util-position-from-estree@2.0.0:
+ resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==}
+
unist-util-position@4.0.4:
resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==}
+ unist-util-position@5.0.0:
+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+
+ unist-util-remove@3.1.1:
+ resolution: {integrity: sha512-kfCqZK5YVY5yEa89tvpl7KnBBHu2c6CzMkqHUrlOqaRgGOMp0sMvwWOVrbAtj03KhovQB7i96Gda72v/EFE0vw==}
+
unist-util-stringify-position@3.0.3:
resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==}
+ unist-util-stringify-position@4.0.0:
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+
unist-util-visit-parents@5.1.3:
resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==}
+ unist-util-visit-parents@6.0.2:
+ resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==}
+
unist-util-visit@4.1.2:
resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==}
+ unist-util-visit@5.0.0:
+ resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+
unrs-resolver@1.11.1:
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
@@ -3510,12 +3860,21 @@ packages:
resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
engines: {'0': node >=0.6.0}
+ vfile-matter@5.0.1:
+ resolution: {integrity: sha512-o6roP82AiX0XfkyTHyRCMXgHfltUNlXSEqCIS80f+mbAyiQBE2fxtDVMtseyytGx75sihiJFo/zR6r/4LTs2Cw==}
+
vfile-message@3.1.4:
resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==}
+ vfile-message@4.0.3:
+ resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==}
+
vfile@5.3.7:
resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==}
+ vfile@6.0.3:
+ resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
+
vite-node@3.2.4:
resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
@@ -3659,6 +4018,11 @@ packages:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
+ yaml@2.8.2:
+ resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
+ engines: {node: '>= 14.6'}
+ hasBin: true
+
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
@@ -3666,6 +4030,9 @@ packages:
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
+ zwitch@2.0.4:
+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+
snapshots:
'@babel/code-frame@7.27.1':
@@ -4286,6 +4653,42 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@mdx-js/mdx@3.1.1':
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdx': 2.0.13
+ acorn: 8.15.0
+ collapse-white-space: 2.1.0
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ estree-util-scope: 1.0.0
+ estree-walker: 3.0.3
+ hast-util-to-jsx-runtime: 2.3.6
+ markdown-extensions: 2.0.0
+ recma-build-jsx: 1.0.0
+ recma-jsx: 1.0.1(acorn@8.15.0)
+ recma-stringify: 1.0.0
+ rehype-recma: 1.0.0
+ remark-mdx: 3.1.1
+ remark-parse: 11.0.0
+ remark-rehype: 11.1.2
+ source-map: 0.7.6
+ unified: 11.0.5
+ unist-util-position-from-estree: 2.0.0
+ unist-util-stringify-position: 4.0.0
+ unist-util-visit: 5.0.0
+ vfile: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@mdx-js/react@3.1.1(@types/react@18.3.23)(react@18.3.1)':
+ dependencies:
+ '@types/mdx': 2.0.13
+ '@types/react': 18.3.23
+ react: 18.3.1
+
'@napi-rs/wasm-runtime@0.2.12':
dependencies:
'@emnapi/core': 1.7.1
@@ -4457,6 +4860,10 @@ snapshots:
'@types/deep-eql@4.0.2': {}
+ '@types/estree-jsx@1.0.5':
+ dependencies:
+ '@types/estree': 1.0.8
+
'@types/estree@1.0.8': {}
'@types/formidable@2.0.6':
@@ -4469,6 +4876,10 @@ snapshots:
dependencies:
'@types/unist': 2.0.11
+ '@types/hast@3.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
'@types/jsforce@1.11.5':
dependencies:
'@types/node': 17.0.0
@@ -4498,6 +4909,12 @@ snapshots:
dependencies:
'@types/unist': 2.0.11
+ '@types/mdast@4.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/mdx@2.0.13': {}
+
'@types/ms@2.1.0': {}
'@types/node@17.0.0': {}
@@ -4535,6 +4952,8 @@ snapshots:
'@types/unist@2.0.11': {}
+ '@types/unist@3.0.3': {}
+
'@types/validator@13.15.2': {}
'@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2)':
@@ -4690,13 +5109,13 @@ snapshots:
chai: 5.3.3
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@17.0.0)(tsx@4.21.0))':
+ '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
- vite: 7.3.1(@types/node@17.0.0)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/pretty-format@3.2.4':
dependencies:
@@ -4765,6 +5184,10 @@ snapshots:
ansi-styles@6.2.3: {}
+ argparse@1.0.10:
+ dependencies:
+ sprintf-js: 1.0.3
+
argparse@2.0.1: {}
aria-hidden@1.2.6:
@@ -4856,6 +5279,8 @@ snapshots:
ast-types-flow@0.0.8: {}
+ astring@1.9.0: {}
+
async-function@1.0.0: {}
asynckit@0.4.0: {}
@@ -4944,6 +5369,8 @@ snapshots:
caseless@0.12.0: {}
+ ccount@2.0.1: {}
+
chai@5.3.3:
dependencies:
assertion-error: 2.0.1
@@ -4981,8 +5408,14 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
+ character-entities-html4@2.1.0: {}
+
+ character-entities-legacy@3.0.0: {}
+
character-entities@2.0.2: {}
+ character-reference-invalid@2.0.1: {}
+
check-error@2.1.3: {}
client-only@0.0.1: {}
@@ -4993,6 +5426,8 @@ snapshots:
coffeescript@1.12.7: {}
+ collapse-white-space@2.1.0: {}
+
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@@ -5139,6 +5574,10 @@ snapshots:
detect-node-es@1.1.0: {}
+ devlop@1.1.0:
+ dependencies:
+ dequal: 2.0.3
+
dezalgo@1.0.4:
dependencies:
asap: 2.0.6
@@ -5295,6 +5734,20 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
+ esast-util-from-estree@2.0.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ devlop: 1.1.0
+ estree-util-visit: 2.0.0
+ unist-util-position-from-estree: 2.0.0
+
+ esast-util-from-js@2.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ acorn: 8.15.0
+ esast-util-from-estree: 2.0.0
+ vfile-message: 4.0.3
+
esbuild@0.27.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.2
@@ -5519,6 +5972,8 @@ snapshots:
acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 3.4.3
+ esprima@4.0.1: {}
+
esquery@1.6.0:
dependencies:
estraverse: 5.3.0
@@ -5531,6 +5986,35 @@ snapshots:
estraverse@5.3.0: {}
+ estree-util-attach-comments@3.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ estree-util-build-jsx@3.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ estree-walker: 3.0.3
+
+ estree-util-is-identifier-name@3.0.0: {}
+
+ estree-util-scope@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+
+ estree-util-to-js@2.0.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ astring: 1.9.0
+ source-map: 0.7.6
+
+ estree-util-visit@2.0.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/unist': 3.0.3
+
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.8
@@ -5541,6 +6025,10 @@ snapshots:
expect-type@1.3.0: {}
+ extend-shallow@2.0.1:
+ dependencies:
+ is-extendable: 0.1.1
+
extend@3.0.2: {}
extsprintf@1.3.0: {}
@@ -5743,6 +6231,8 @@ snapshots:
dependencies:
assert-plus: 1.0.0
+ github-slugger@2.0.0: {}
+
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -5821,6 +6311,13 @@ snapshots:
graphemer@1.4.0: {}
+ gray-matter@4.0.3:
+ dependencies:
+ js-yaml: 3.14.2
+ kind-of: 6.0.3
+ section-matter: 1.0.0
+ strip-bom-string: 1.0.0
+
gtoken@5.3.2:
dependencies:
gaxios: 4.3.3
@@ -5859,8 +6356,61 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ hast-util-heading-rank@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-to-estree@3.1.3:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ estree-util-attach-comments: 3.0.0
+ estree-util-is-identifier-name: 3.0.0
+ hast-util-whitespace: 3.0.0
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ style-to-js: 1.1.21
+ unist-util-position: 5.0.0
+ zwitch: 2.0.4
+ transitivePeerDependencies:
+ - supports-color
+
+ hast-util-to-jsx-runtime@2.3.6:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ hast-util-whitespace: 3.0.0
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ style-to-js: 1.1.21
+ unist-util-position: 5.0.0
+ vfile-message: 4.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ hast-util-to-string@3.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+
hast-util-whitespace@2.0.1: {}
+ hast-util-whitespace@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
hoist-non-react-statics@3.3.2:
dependencies:
react-is: 16.13.1
@@ -5898,12 +6448,21 @@ snapshots:
inline-style-parser@0.1.1: {}
+ inline-style-parser@0.2.7: {}
+
internal-slot@1.1.0:
dependencies:
es-errors: 1.3.0
hasown: 2.0.2
side-channel: 1.1.0
+ is-alphabetical@2.0.1: {}
+
+ is-alphanumerical@2.0.1:
+ dependencies:
+ is-alphabetical: 2.0.1
+ is-decimal: 2.0.1
+
is-array-buffer@3.0.5:
dependencies:
call-bind: 1.0.8
@@ -5954,6 +6513,10 @@ snapshots:
call-bound: 1.0.4
has-tostringtag: 1.0.2
+ is-decimal@2.0.1: {}
+
+ is-extendable@0.1.1: {}
+
is-extglob@2.1.1: {}
is-finalizationregistry@1.1.1:
@@ -5974,6 +6537,8 @@ snapshots:
dependencies:
is-extglob: 2.1.1
+ is-hexadecimal@2.0.1: {}
+
is-map@2.0.3: {}
is-negative-zero@2.0.3: {}
@@ -6061,6 +6626,11 @@ snapshots:
js-tokens@9.0.1: {}
+ js-yaml@3.14.2:
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
@@ -6162,6 +6732,8 @@ snapshots:
dependencies:
json-buffer: 3.0.1
+ kind-of@6.0.3: {}
+
kleur@4.1.5: {}
language-subtag-registry@0.3.23: {}
@@ -6203,6 +6775,8 @@ snapshots:
lodash@4.17.21: {}
+ longest-streak@3.1.0: {}
+
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
@@ -6223,6 +6797,8 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
+ markdown-extensions@2.0.0: {}
+
math-intrinsics@1.1.0: {}
mdast-util-definitions@5.1.2:
@@ -6248,6 +6824,77 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ mdast-util-from-markdown@2.0.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ decode-named-character-reference: 1.2.0
+ devlop: 1.1.0
+ mdast-util-to-string: 4.0.0
+ micromark: 4.0.2
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-decode-string: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ unist-util-stringify-position: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdx-expression@2.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdx-jsx@3.2.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ parse-entities: 4.0.2
+ stringify-entities: 4.0.4
+ unist-util-stringify-position: 4.0.0
+ vfile-message: 4.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdx@3.0.0:
+ dependencies:
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdxjs-esm@2.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-phrasing@4.1.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ unist-util-is: 6.0.1
+
mdast-util-to-hast@12.3.0:
dependencies:
'@types/hast': 2.3.10
@@ -6259,10 +6906,38 @@ snapshots:
unist-util-position: 4.0.4
unist-util-visit: 4.1.2
+ mdast-util-to-hast@13.2.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@ungap/structured-clone': 1.3.0
+ devlop: 1.1.0
+ micromark-util-sanitize-uri: 2.0.1
+ trim-lines: 3.0.1
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.0.0
+ vfile: 6.0.3
+
+ mdast-util-to-markdown@2.1.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ longest-streak: 3.1.0
+ mdast-util-phrasing: 4.1.0
+ mdast-util-to-string: 4.0.0
+ micromark-util-classify-character: 2.0.1
+ micromark-util-decode-string: 2.0.1
+ unist-util-visit: 5.0.0
+ zwitch: 2.0.4
+
mdast-util-to-string@3.2.0:
dependencies:
'@types/mdast': 3.0.15
+ mdast-util-to-string@4.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+
memoize-one@6.0.0: {}
merge2@1.4.1: {}
@@ -6288,12 +6963,88 @@ snapshots:
micromark-util-types: 1.1.0
uvu: 0.5.6
+ micromark-core-commonmark@2.0.3:
+ dependencies:
+ decode-named-character-reference: 1.2.0
+ devlop: 1.1.0
+ micromark-factory-destination: 2.0.1
+ micromark-factory-label: 2.0.1
+ micromark-factory-space: 2.0.1
+ micromark-factory-title: 2.0.1
+ micromark-factory-whitespace: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-html-tag-name: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-subtokenize: 2.1.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-mdx-expression@3.0.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ micromark-factory-mdx-expression: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-mdx-jsx@3.0.2:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ micromark-factory-mdx-expression: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ vfile-message: 4.0.3
+
+ micromark-extension-mdx-md@2.0.0:
+ dependencies:
+ micromark-util-types: 2.0.2
+
+ micromark-extension-mdxjs-esm@3.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ unist-util-position-from-estree: 2.0.0
+ vfile-message: 4.0.3
+
+ micromark-extension-mdxjs@3.0.0:
+ dependencies:
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
+ micromark-extension-mdx-expression: 3.0.1
+ micromark-extension-mdx-jsx: 3.0.2
+ micromark-extension-mdx-md: 2.0.0
+ micromark-extension-mdxjs-esm: 3.0.0
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-factory-destination@1.1.0:
dependencies:
micromark-util-character: 1.2.0
micromark-util-symbol: 1.1.0
micromark-util-types: 1.1.0
+ micromark-factory-destination@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-factory-label@1.1.0:
dependencies:
micromark-util-character: 1.2.0
@@ -6301,11 +7052,35 @@ snapshots:
micromark-util-types: 1.1.0
uvu: 0.5.6
+ micromark-factory-label@2.0.1:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-mdx-expression@2.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ unist-util-position-from-estree: 2.0.0
+ vfile-message: 4.0.3
+
micromark-factory-space@1.1.0:
dependencies:
micromark-util-character: 1.2.0
micromark-util-types: 1.1.0
+ micromark-factory-space@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-types: 2.0.2
+
micromark-factory-title@1.1.0:
dependencies:
micromark-factory-space: 1.1.0
@@ -6313,6 +7088,13 @@ snapshots:
micromark-util-symbol: 1.1.0
micromark-util-types: 1.1.0
+ micromark-factory-title@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-factory-whitespace@1.1.0:
dependencies:
micromark-factory-space: 1.1.0
@@ -6320,30 +7102,61 @@ snapshots:
micromark-util-symbol: 1.1.0
micromark-util-types: 1.1.0
+ micromark-factory-whitespace@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-util-character@1.2.0:
dependencies:
micromark-util-symbol: 1.1.0
micromark-util-types: 1.1.0
+ micromark-util-character@2.1.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-util-chunked@1.1.0:
dependencies:
micromark-util-symbol: 1.1.0
+ micromark-util-chunked@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
micromark-util-classify-character@1.1.0:
dependencies:
micromark-util-character: 1.2.0
micromark-util-symbol: 1.1.0
micromark-util-types: 1.1.0
+ micromark-util-classify-character@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-util-combine-extensions@1.1.0:
dependencies:
micromark-util-chunked: 1.1.0
micromark-util-types: 1.1.0
+ micromark-util-combine-extensions@2.0.1:
+ dependencies:
+ micromark-util-chunked: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-util-decode-numeric-character-reference@1.1.0:
dependencies:
micromark-util-symbol: 1.1.0
+ micromark-util-decode-numeric-character-reference@2.0.2:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
micromark-util-decode-string@1.1.0:
dependencies:
decode-named-character-reference: 1.2.0
@@ -6351,24 +7164,59 @@ snapshots:
micromark-util-decode-numeric-character-reference: 1.1.0
micromark-util-symbol: 1.1.0
+ micromark-util-decode-string@2.0.1:
+ dependencies:
+ decode-named-character-reference: 1.2.0
+ micromark-util-character: 2.1.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-symbol: 2.0.1
+
micromark-util-encode@1.1.0: {}
+ micromark-util-encode@2.0.1: {}
+
+ micromark-util-events-to-acorn@2.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/unist': 3.0.3
+ devlop: 1.1.0
+ estree-util-visit: 2.0.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ vfile-message: 4.0.3
+
micromark-util-html-tag-name@1.2.0: {}
+ micromark-util-html-tag-name@2.0.1: {}
+
micromark-util-normalize-identifier@1.1.0:
dependencies:
micromark-util-symbol: 1.1.0
+ micromark-util-normalize-identifier@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
micromark-util-resolve-all@1.1.0:
dependencies:
micromark-util-types: 1.1.0
+ micromark-util-resolve-all@2.0.1:
+ dependencies:
+ micromark-util-types: 2.0.2
+
micromark-util-sanitize-uri@1.2.0:
dependencies:
micromark-util-character: 1.2.0
micromark-util-encode: 1.1.0
micromark-util-symbol: 1.1.0
+ micromark-util-sanitize-uri@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-encode: 2.0.1
+ micromark-util-symbol: 2.0.1
+
micromark-util-subtokenize@1.1.0:
dependencies:
micromark-util-chunked: 1.1.0
@@ -6376,10 +7224,21 @@ snapshots:
micromark-util-types: 1.1.0
uvu: 0.5.6
+ micromark-util-subtokenize@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-util-symbol@1.1.0: {}
+ micromark-util-symbol@2.0.1: {}
+
micromark-util-types@1.1.0: {}
+ micromark-util-types@2.0.2: {}
+
micromark@3.2.0:
dependencies:
'@types/debug': 4.1.12
@@ -6402,6 +7261,28 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ micromark@4.0.2:
+ dependencies:
+ '@types/debug': 4.1.12
+ debug: 4.4.3
+ decode-named-character-reference: 1.2.0
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-encode: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-subtokenize: 2.1.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
micromatch@4.0.8:
dependencies:
braces: 3.0.3
@@ -6450,6 +7331,19 @@ snapshots:
natural-compare@1.4.0: {}
+ next-mdx-remote@5.0.0(@types/react@18.3.23)(react@18.3.1):
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@mdx-js/mdx': 3.1.1
+ '@mdx-js/react': 3.1.1(@types/react@18.3.23)(react@18.3.1)
+ react: 18.3.1
+ unist-util-remove: 3.1.1
+ vfile: 6.0.3
+ vfile-matter: 5.0.1
+ transitivePeerDependencies:
+ - '@types/react'
+ - supports-color
+
next-sitemap@2.5.28(next@14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
dependencies:
'@corex/deepmerge': 2.6.148
@@ -6568,6 +7462,16 @@ snapshots:
dependencies:
callsites: 3.1.0
+ parse-entities@4.0.2:
+ dependencies:
+ '@types/unist': 2.0.11
+ character-entities-legacy: 3.0.0
+ character-reference-invalid: 2.0.1
+ decode-named-character-reference: 1.2.0
+ is-alphanumerical: 2.0.1
+ is-decimal: 2.0.1
+ is-hexadecimal: 2.0.1
+
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.27.1
@@ -6636,6 +7540,8 @@ snapshots:
property-information@6.5.0: {}
+ property-information@7.1.0: {}
+
psl@1.15.0:
dependencies:
punycode: 2.3.1
@@ -6785,6 +7691,35 @@ snapshots:
string_decoder: 1.1.1
util-deprecate: 1.0.2
+ recma-build-jsx@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-util-build-jsx: 3.0.1
+ vfile: 6.0.3
+
+ recma-jsx@1.0.1(acorn@8.15.0):
+ dependencies:
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
+ estree-util-to-js: 2.0.0
+ recma-parse: 1.0.0
+ recma-stringify: 1.0.0
+ unified: 11.0.5
+
+ recma-parse@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ esast-util-from-js: 2.0.1
+ unified: 11.0.5
+ vfile: 6.0.3
+
+ recma-stringify@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-util-to-js: 2.0.0
+ unified: 11.0.5
+ vfile: 6.0.3
+
redaxios@0.4.1: {}
reflect.getprototypeof@1.0.10:
@@ -6807,6 +7742,29 @@ snapshots:
gopd: 1.2.0
set-function-name: 2.0.2
+ rehype-recma@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/hast': 3.0.4
+ hast-util-to-estree: 3.1.3
+ transitivePeerDependencies:
+ - supports-color
+
+ rehype-slug@6.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ github-slugger: 2.0.0
+ hast-util-heading-rank: 3.0.0
+ hast-util-to-string: 3.0.1
+ unist-util-visit: 5.0.0
+
+ remark-mdx@3.1.1:
+ dependencies:
+ mdast-util-mdx: 3.0.0
+ micromark-extension-mdxjs: 3.0.0
+ transitivePeerDependencies:
+ - supports-color
+
remark-parse@10.0.2:
dependencies:
'@types/mdast': 3.0.15
@@ -6815,6 +7773,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ remark-parse@11.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-from-markdown: 2.0.2
+ micromark-util-types: 2.0.2
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+
remark-rehype@10.1.0:
dependencies:
'@types/hast': 2.3.10
@@ -6822,6 +7789,14 @@ snapshots:
mdast-util-to-hast: 12.3.0
unified: 10.1.2
+ remark-rehype@11.1.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ mdast-util-to-hast: 13.2.1
+ unified: 11.0.5
+ vfile: 6.0.3
+
request@2.88.2:
dependencies:
aws-sign2: 0.7.0
@@ -6943,6 +7918,11 @@ snapshots:
dependencies:
loose-envify: 1.4.0
+ section-matter@1.0.0:
+ dependencies:
+ extend-shallow: 2.0.1
+ kind-of: 6.0.3
+
semver@6.3.1: {}
semver@7.7.2: {}
@@ -7047,8 +8027,12 @@ snapshots:
source-map@0.5.7: {}
+ source-map@0.7.6: {}
+
space-separated-tokens@2.0.2: {}
+ sprintf-js@1.0.3: {}
+
sshpk@1.18.0:
dependencies:
asn1: 0.2.6
@@ -7140,6 +8124,11 @@ snapshots:
dependencies:
safe-buffer: 5.1.2
+ stringify-entities@4.0.4:
+ dependencies:
+ character-entities-html4: 2.1.0
+ character-entities-legacy: 3.0.0
+
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
@@ -7148,6 +8137,8 @@ snapshots:
dependencies:
ansi-regex: 6.2.2
+ strip-bom-string@1.0.0: {}
+
strip-bom@3.0.0: {}
strip-json-comments@3.1.1: {}
@@ -7156,10 +8147,18 @@ snapshots:
dependencies:
js-tokens: 9.0.1
+ style-to-js@1.1.21:
+ dependencies:
+ style-to-object: 1.0.14
+
style-to-object@0.4.4:
dependencies:
inline-style-parser: 0.1.1
+ style-to-object@1.0.14:
+ dependencies:
+ inline-style-parser: 0.2.7
+
styled-jsx@5.1.1(react@18.3.1):
dependencies:
client-only: 0.0.1
@@ -7323,31 +8322,74 @@ snapshots:
trough: 2.2.0
vfile: 5.3.7
+ unified@11.0.5:
+ dependencies:
+ '@types/unist': 3.0.3
+ bail: 2.0.2
+ devlop: 1.1.0
+ extend: 3.0.2
+ is-plain-obj: 4.1.0
+ trough: 2.2.0
+ vfile: 6.0.3
+
unist-util-generated@2.0.1: {}
unist-util-is@5.2.1:
dependencies:
'@types/unist': 2.0.11
+ unist-util-is@6.0.1:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-position-from-estree@2.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
unist-util-position@4.0.4:
dependencies:
'@types/unist': 2.0.11
+ unist-util-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-remove@3.1.1:
+ dependencies:
+ '@types/unist': 2.0.11
+ unist-util-is: 5.2.1
+ unist-util-visit-parents: 5.1.3
+
unist-util-stringify-position@3.0.3:
dependencies:
'@types/unist': 2.0.11
+ unist-util-stringify-position@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
unist-util-visit-parents@5.1.3:
dependencies:
'@types/unist': 2.0.11
unist-util-is: 5.2.1
+ unist-util-visit-parents@6.0.2:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+
unist-util-visit@4.1.2:
dependencies:
'@types/unist': 2.0.11
unist-util-is: 5.2.1
unist-util-visit-parents: 5.1.3
+ unist-util-visit@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+ unist-util-visit-parents: 6.0.2
+
unrs-resolver@1.11.1:
dependencies:
napi-postinstall: 0.3.4
@@ -7416,11 +8458,21 @@ snapshots:
core-util-is: 1.0.2
extsprintf: 1.3.0
+ vfile-matter@5.0.1:
+ dependencies:
+ vfile: 6.0.3
+ yaml: 2.8.2
+
vfile-message@3.1.4:
dependencies:
'@types/unist': 2.0.11
unist-util-stringify-position: 3.0.3
+ vfile-message@4.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-stringify-position: 4.0.0
+
vfile@5.3.7:
dependencies:
'@types/unist': 2.0.11
@@ -7428,13 +8480,18 @@ snapshots:
unist-util-stringify-position: 3.0.3
vfile-message: 3.1.4
- vite-node@3.2.4(@types/node@17.0.0)(tsx@4.21.0):
+ vfile@6.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile-message: 4.0.3
+
+ vite-node@3.2.4(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 2.0.3
- vite: 7.3.1(@types/node@17.0.0)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- '@types/node'
- jiti
@@ -7449,7 +8506,7 @@ snapshots:
- tsx
- yaml
- vite@7.3.1(@types/node@17.0.0)(tsx@4.21.0):
+ vite@7.3.1(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.27.2
fdir: 6.5.0(picomatch@4.0.3)
@@ -7461,12 +8518,13 @@ snapshots:
'@types/node': 17.0.0
fsevents: 2.3.3
tsx: 4.21.0
+ yaml: 2.8.2
- vitest@3.2.4(@types/debug@4.1.12)(@types/node@17.0.0)(tsx@4.21.0):
+ vitest@3.2.4(@types/debug@4.1.12)(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@17.0.0)(tsx@4.21.0))
+ '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
@@ -7484,8 +8542,8 @@ snapshots:
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
- vite: 7.3.1(@types/node@17.0.0)(tsx@4.21.0)
- vite-node: 3.2.4(@types/node@17.0.0)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2)
+ vite-node: 3.2.4(@types/node@17.0.0)(tsx@4.21.0)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/debug': 4.1.12
@@ -7596,6 +8654,10 @@ snapshots:
yaml@1.10.2: {}
+ yaml@2.8.2: {}
+
yocto-queue@0.1.0: {}
zod@3.25.76: {}
+
+ zwitch@2.0.4: {}
diff --git a/src/components/Banners.tsx b/src/components/Banners.tsx
index c2349631..a8ee8ee9 100644
--- a/src/components/Banners.tsx
+++ b/src/components/Banners.tsx
@@ -1,28 +1,34 @@
import { FC } from 'react';
-// import { useRouter } from 'next/router';
+import { useRouter } from 'next/router';
+import { Box, Flex, Icon } from '@chakra-ui/react';
+import { ChevronRightIcon } from '@chakra-ui/icons';
-// import { Banner } from './UI';
+import { BannerClickeable } from './UI';
+import { ROUNDS_URL } from '../constants';
+
+// TODO: Replace with server components when available
+const ACTIVE_ROUND = {
+ slug: 'agr26',
+ name: 'Academic Grants Round 2026'
+};
-// TODO: Add banner content
export const Banners: FC = () => {
- // const router = useRouter();
+ const router = useRouter();
- // if (
- // !router.pathname.includes(TEN_YEAR_ANNIVERSARY_URL) &&
- // !router.pathname.includes(DEVCON_GRANTS_URL)
- // ) {
- // return (
- //
- //
- // Applications for the{' '}
- //
- // Destino Devconnect Support
- // {' '}
- // are now open!
- //
- //
- // );
- // }
+ // Don't show banner on the round page itself
+ if (router.pathname.startsWith(ROUNDS_URL)) {
+ return null;
+ }
- return null;
+ return (
+
+
+ {ACTIVE_ROUND.name} is now open!
+
+ Apply now
+
+
+
+
+ );
};
diff --git a/src/components/Nav.tsx b/src/components/Nav.tsx
index 3b3d882e..aa173c0c 100644
--- a/src/components/Nav.tsx
+++ b/src/components/Nav.tsx
@@ -36,17 +36,18 @@ export const Nav: FC = () => {
return (
-
+
router.push(HOME_URL)}
cursor={isOpen ? 'default' : 'pointer'}
sx={isOpen ? { transitionDelay: '0.15s', filter: 'brightness(10)' } : undefined}
- zIndex={9999}
+ position='relative'
+ zIndex='modal'
>
-
+
-
-
+ {/* Desktop Layout */}
+
+ {/* Background Image Container */}
+
-
-
-
-
-
-
+ {/* Gradient Overlay - fades to white for smooth transition to content */}
+
+ {/* Content Box - Positioned over the image, accounting for nav and content overlap */}
+
+
+
+ {title}
+
+
+ {subheading && (
+
+ {subheading}
+
+ )}
+
+ {children}
+
+
-
+
);
};
diff --git a/src/components/UI/common/Banner.tsx b/src/components/UI/common/Banner.tsx
index b5773cd8..07cc2a8c 100644
--- a/src/components/UI/common/Banner.tsx
+++ b/src/components/UI/common/Banner.tsx
@@ -15,6 +15,8 @@ export const Banner: FC = ({ children, ...props }) => {
alignItems='center'
bg='brand.accent'
color='white'
+ position='relative'
+ zIndex='banner'
{...props}
>
{children}
diff --git a/src/components/forms/GrantInitiativeSelection.tsx b/src/components/forms/GrantInitiativeSelection.tsx
new file mode 100644
index 00000000..f00414e4
--- /dev/null
+++ b/src/components/forms/GrantInitiativeSelection.tsx
@@ -0,0 +1,258 @@
+import {
+ Box,
+ chakra,
+ Flex,
+ Grid,
+ GridItem,
+ Heading,
+ Icon,
+ Link,
+ List,
+ ListItem,
+ Menu,
+ MenuButton,
+ MenuItem,
+ MenuList,
+ Stack,
+ Text,
+ Wrap,
+ WrapItem,
+ Tag
+} from '@chakra-ui/react';
+import { FC, useMemo, useState, useEffect } from 'react';
+import { LayoutGrid, Rows3 } from 'lucide-react';
+
+import { GrantInitiative } from '../../types';
+import { SelectArrowIcon } from '../UI/icons';
+
+const Button = chakra('button');
+
+interface GrantInitiativeSelectionProps {
+ items: GrantInitiative[];
+ getItemUrl: (item: GrantInitiative) => string;
+ paramTags?: string[];
+ emptyStateTitle?: string;
+ emptyStateMessage?: string;
+}
+
+export const GrantInitiativeSelection: FC = ({
+ items,
+ getItemUrl,
+ paramTags,
+ emptyStateTitle = 'No Items Available',
+ emptyStateMessage = 'There are currently no active items available for application.'
+}) => {
+ const [selectedTags, setSelectedTags] = useState(paramTags ? paramTags : []);
+ const [displayFormat, setDisplayFormat] = useState<'grid' | 'table'>('grid');
+
+ const tagOptions = useMemo(() => {
+ return Array.from(new Set(items.reduce((acc, item) => {
+ item.Tags__c?.split(';').forEach(tag => {
+ acc.push(tag.trim());
+ });
+ return acc;
+ }, [] as string[]).filter(Boolean)));
+ }, [items]);
+
+ // Sync selectedTags with paramTags when paramTags changes
+ useEffect(() => {
+ if (paramTags) {
+ // Validate paramTags against available tagOptions
+ const validTags = paramTags.filter(tag => tagOptions.includes(tag));
+ setSelectedTags(validTags);
+ }
+ }, [paramTags, tagOptions]);
+
+ const handleToggleTag = (tag: string) => {
+ setSelectedTags(prev =>
+ prev.includes(tag)
+ ? prev.filter(t => t !== tag)
+ : [...prev, tag]
+ );
+ };
+
+ const handleClearAllTags = () => {
+ setSelectedTags([]);
+ };
+
+ const filteredItems = useMemo(() => {
+ return items.filter(item =>
+ selectedTags.length === 0
+ ? true
+ : selectedTags.some(tag => item.Tags__c?.includes(tag))
+ );
+ }, [items, selectedTags]);
+
+ if (items.length === 0) {
+ return (
+
+
+
+
+ {emptyStateTitle}
+
+
+ {emptyStateMessage}
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+ setDisplayFormat('grid')} _hover={{ color: 'brand.hover' }} />
+ setDisplayFormat('table')} _hover={{ color: 'brand.hover' }} />
+
+
+
+ {selectedTags.length > 0 && (
+
+
+ Selected tags:
+
+
+ {selectedTags.map(tag => (
+
+ handleToggleTag(tag)}
+ _hover={{ opacity: 0.8 }}
+ >
+ {tag} ×
+
+
+ ))}
+
+
+ )}
+
+ {displayFormat === 'grid' && (
+
+ {filteredItems.map(item => (
+
+
+
+
+ {item.Name}
+
+
+
+ {item.Description__c}
+
+
+
+
+ ))}
+
+ )}
+
+ {displayFormat === 'table' && (
+
+ {filteredItems.map(item => (
+
+
+
+ {item.Name}
+
+
+ {item.Tags__c?.split(';').map(tag => tag.trim()).map(tag => (
+ {tag}
+ ))}
+
+
+
+ ))}
+
+ )}
+
+ );
+};
diff --git a/src/components/forms/RFPSelection.tsx b/src/components/forms/RFPSelection.tsx
index fba5a1b4..a21fb0f0 100644
--- a/src/components/forms/RFPSelection.tsx
+++ b/src/components/forms/RFPSelection.tsx
@@ -1,31 +1,11 @@
-import {
- Box,
- chakra,
- Flex,
- Grid,
- GridItem,
- Heading,
- Icon,
- Link,
- List,
- ListItem,
- Menu,
- MenuButton,
- MenuItem,
- MenuList,
- Stack,
- Text,
- Wrap,
- WrapItem,
- Tag
-} from '@chakra-ui/react';
-import { FC, useMemo, useState, useEffect } from 'react';
-import { LayoutGrid, Rows3 } from 'lucide-react';
+import { FC } from 'react';
+import { GrantInitiativeSelection } from './GrantInitiativeSelection';
import { RFPItem } from './schemas/RFP';
-import { SelectArrowIcon } from '../UI/icons';
+import { GrantInitiative } from '../../types';
-const Button = chakra('button');
+const getRFPUrl = (item: GrantInitiative) =>
+ `/applicants/rfp/${item.Custom_URL_Slug__c || item.Id}`;
interface RFPSelectionProps {
rfpItems: RFPItem[];
@@ -33,197 +13,13 @@ interface RFPSelectionProps {
}
export const RFPSelection: FC = ({ rfpItems, paramTags }) => {
- const [selectedTags, setSelectedTags] = useState(paramTags ? paramTags : []);
- const [displayFormat, setDisplayFormat] = useState<'grid' | 'table'>('grid');
-
- const tagOptions = useMemo(() => {
- return Array.from(new Set(rfpItems.reduce((acc, item) => {
- item.Tags__c?.split(';').forEach(tag => {
- acc.push(tag.trim());
- });
- return acc;
- }, [] as string[]).filter(Boolean)));
- }, [rfpItems]);
-
- // Sync selectedTags with paramTags when paramTags changes
- useEffect(() => {
- if (paramTags) {
- // Validate paramTags against available tagOptions
- const validTags = paramTags.filter(tag => tagOptions.includes(tag));
- setSelectedTags(validTags);
- }
- }, [paramTags, tagOptions]);
-
- const handleToggleTag = (tag: string) => {
- setSelectedTags(prev =>
- prev.includes(tag)
- ? prev.filter(t => t !== tag)
- : [...prev, tag]
- );
- };
-
- const handleClearAllTags = () => {
- setSelectedTags([]);
- };
-
- if (rfpItems.length === 0) {
- return (
-
-
- No RFP Items Available
-
- There are currently no active Request for Proposals available for application.
-
- );
- }
-
return (
-
-
-
-
- setDisplayFormat('grid')} _hover={{ color: 'brand.hover' }} />
- setDisplayFormat('table')} _hover={{ color: 'brand.hover' }} />
-
-
-
- {selectedTags.length > 0 && (
-
-
- Selected tags:
-
-
- {selectedTags.map(tag => (
-
- handleToggleTag(tag)}
- _hover={{ opacity: 0.8 }}
- >
- {tag} ×
-
-
- ))}
-
-
- )}
-
- {displayFormat === 'grid' && (
-
- {rfpItems.filter(item =>
- selectedTags.length === 0
- ? true
- : selectedTags.some(tag => item.Tags__c?.includes(tag))
- ).map(item => (
-
-
-
-
- {item.Name}
-
-
- {item.Category__c && (
-
- {item.Category__c}
-
- )}
-
-
- {item.Description__c}
-
-
-
-
- ))}
-
- )}
-
- {displayFormat === 'table' && (
-
- {rfpItems.filter(item =>
- selectedTags.length === 0
- ? true
- : selectedTags.some(tag => item.Tags__c?.includes(tag))
- ).map(item => (
-
-
-
- {item.Name}
-
- {item.Tags__c?.split(';').map(tag => tag.trim()).map(tag => {tag})}
-
-
- ))}
-
- )}
-
+
);
};
diff --git a/src/components/forms/WishlistSelection.tsx b/src/components/forms/WishlistSelection.tsx
index 1006f56a..5c941a1e 100644
--- a/src/components/forms/WishlistSelection.tsx
+++ b/src/components/forms/WishlistSelection.tsx
@@ -1,31 +1,11 @@
-import {
- Box,
- chakra,
- Flex,
- Grid,
- GridItem,
- Heading,
- Icon,
- Link,
- List,
- ListItem,
- Menu,
- MenuButton,
- MenuItem,
- MenuList,
- Stack,
- Text,
- Wrap,
- WrapItem,
- Tag,
-} from '@chakra-ui/react';
-import { FC, useMemo, useState, useEffect } from 'react';
-import { LayoutGrid, Rows3 } from 'lucide-react';
+import { FC } from 'react';
+import { GrantInitiativeSelection } from './GrantInitiativeSelection';
import { WishlistItem } from './schemas/Wishlist';
-import { SelectArrowIcon } from '../UI/icons';
+import { GrantInitiative } from '../../types';
-const Button = chakra('button');
+const getWishlistUrl = (item: GrantInitiative) =>
+ `/applicants/wishlist/${item.Custom_URL_Slug__c || item.Id}`;
interface WishlistSelectionProps {
wishlistItems: WishlistItem[];
@@ -33,196 +13,13 @@ interface WishlistSelectionProps {
}
export const WishlistSelection: FC = ({ wishlistItems, paramTags }) => {
- const [selectedTags, setSelectedTags] = useState(paramTags ? paramTags : []);
- const [displayFormat, setDisplayFormat] = useState<'grid' | 'table'>('grid');
-
- const tagOptions = useMemo(() => {
- return Array.from(new Set(wishlistItems.reduce((acc, item) => {
- item.Tags__c?.split(';').forEach(tag => {
- acc.push(tag.trim());
- });
- return acc;
- }, [] as string[]).filter(Boolean)));
- }, [wishlistItems]);
-
- // Sync selectedTags with paramTags when paramTags changes
- useEffect(() => {
- if (paramTags) {
- // Validate paramTags against available tagOptions
- const validTags = paramTags.filter(tag => tagOptions.includes(tag));
- setSelectedTags(validTags);
- }
- }, [paramTags, tagOptions]);
-
- const handleToggleTag = (tag: string) => {
- setSelectedTags(prev =>
- prev.includes(tag)
- ? prev.filter(t => t !== tag)
- : [...prev, tag]
- );
- };
-
- const handleClearAllTags = () => {
- setSelectedTags([]);
- };
-
- if (wishlistItems.length === 0) {
- return (
-
-
- No Wishlist Available
-
- There are currently no active wishlists available for application.
-
- );
- }
-
return (
-
-
-
-
- setDisplayFormat('grid')} _hover={{ color: 'brand.hover' }} />
- setDisplayFormat('table')} _hover={{ color: 'brand.hover' }} />
-
-
-
- {selectedTags.length > 0 && (
-
-
- Selected tags:
-
-
- {selectedTags.map(tag => (
-
- handleToggleTag(tag)}
- _hover={{ opacity: 0.8 }}
- >
- {tag} ×
-
-
- ))}
-
-
- )}
-
- {displayFormat === 'grid' && (
-
- {wishlistItems.filter(item =>
- selectedTags.length === 0
- ? true
- : selectedTags.some(tag => item.Tags__c?.includes(tag))
- ).map(item => (
-
-
-
-
- {item.Name}
-
-
- {item.Category__c && (
-
- {item.Category__c}
-
- )}
-
-
- {item.Description__c}
-
-
-
-
- ))}
-
- )}
- {displayFormat === 'table' && (
-
- {wishlistItems.filter(item =>
- selectedTags.length === 0
- ? true
- : selectedTags.some(tag => item.Tags__c?.includes(tag))
- ).map(item => (
-
-
-
- {item.Name}
-
- {item.Tags__c?.split(';').map(tag => tag.trim()).map(tag => {tag})}
-
-
- ))}
-
- )}
-
+
);
};
diff --git a/src/components/layout/ApplicantsLayout.tsx b/src/components/layout/ApplicantsLayout.tsx
index bfcc3539..e5fe8220 100644
--- a/src/components/layout/ApplicantsLayout.tsx
+++ b/src/components/layout/ApplicantsLayout.tsx
@@ -11,6 +11,7 @@ import {
APPLICANTS_TABS_MAP,
APPLICANTS_URL,
GRANTEE_FINANCE_URL,
+ OPEN_ROUNDS_URL,
OFFICE_HOURS_URL,
WISHLIST_URL,
RFP_URL
@@ -38,6 +39,10 @@ const getTabIndexFromPath = (pathname: string): number => {
return 3;
}
+ if (pathname.startsWith('/applicants/open-rounds')) {
+ return 4;
+ }
+
if (pathname.startsWith('/applicants')) {
return 0;
}
@@ -99,6 +104,16 @@ export const ApplicantsLayout = ({ children }: Props) => {
);
break;
+ case 4:
+ router.push(
+ {
+ pathname: OPEN_ROUNDS_URL
+ },
+ undefined,
+ { scroll: false }
+ );
+ break;
+
default:
break;
}
diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx
index 10b78bdc..a8d5ad66 100644
--- a/src/components/layout/Layout.tsx
+++ b/src/components/layout/Layout.tsx
@@ -16,12 +16,18 @@ import {
ABOUT_URL,
ACADEMIC_GRANTS_URL,
APPLICANTS_URL,
- HOME_URL
+ HOME_URL,
+ ROUNDS_URL
} from '../../constants';
export const Layout = ({ children, ...props }: ContainerProps) => {
const router = useRouter();
+ // Pages where nav floats over hero image
+ const isHeroPage =
+ router.pathname === ACADEMIC_GRANTS_URL ||
+ router.pathname.startsWith(ROUNDS_URL);
+
const renderContent = (): ReactNode => {
if (router.pathname === HOME_URL) {
return (
@@ -55,22 +61,40 @@ export const Layout = ({ children, ...props }: ContainerProps) => {
if (router.pathname === ACADEMIC_GRANTS_URL) {
return (
-
-
- {children}
-
-
+
+ {children}
+
);
}
+ if (router.pathname.startsWith(ROUNDS_URL)) {
+ return {children};
+ }
+
return children;
};
return (
-
-
-
+ {!isHeroPage && (
+
+
+
+ )}
+
+ {isHeroPage && (
+
+
+
+ )}
{renderContent()}
diff --git a/src/components/rounds/RoundPage.tsx b/src/components/rounds/RoundPage.tsx
new file mode 100644
index 00000000..7a878f68
--- /dev/null
+++ b/src/components/rounds/RoundPage.tsx
@@ -0,0 +1,108 @@
+import { Box, Flex, Stack } from '@chakra-ui/react';
+import { FC } from 'react';
+import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote';
+
+import {
+ ApplicantsSidebar,
+ PageSection,
+ PageMetadata,
+ BannerApplicationClosed,
+ PrivacyPolicyAgreement
+} from '../UI';
+
+import { GrantInitiativeSelection } from '../forms/GrantInitiativeSelection';
+import { GrantsHero } from '../UI/GrantsHero';
+import { GrantInitiative, RoundFrontmatter, SidebarLink } from '../../types';
+import { StaticImageData } from 'next/image';
+import { mdxComponents } from './mdxComponents';
+
+const isRFPItem = (item: GrantInitiative): boolean =>
+ item.RFP_Close_Date__c != null || item.RFP_Open_Date__c != null;
+
+const getItemUrl = (item: GrantInitiative): string => {
+ const type = isRFPItem(item) ? 'rfp' : 'wishlist';
+ return `/applicants/${type}/${item.Custom_URL_Slug__c || item.Id}`;
+};
+
+interface RoundPageProps {
+ frontmatter: RoundFrontmatter;
+ mdxSource: MDXRemoteSerializeResult;
+ items: GrantInitiative[];
+ heroImages: {
+ desktop: StaticImageData;
+ mobile: StaticImageData;
+ };
+ sidebarLinks: SidebarLink[];
+}
+
+export const RoundPage: FC = ({
+ frontmatter,
+ mdxSource,
+ items,
+ heroImages,
+ sidebarLinks
+}) => {
+ const { name, description, status, tag, colorBrand } = frontmatter;
+
+ return (
+ <>
+
+
+
+
+ {description}
+
+
+
+
+ false)}
+ />
+
+
+ {status === 'closed' && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/components/rounds/index.ts b/src/components/rounds/index.ts
new file mode 100644
index 00000000..40d73683
--- /dev/null
+++ b/src/components/rounds/index.ts
@@ -0,0 +1 @@
+export * from './RoundPage';
diff --git a/src/components/rounds/mdxComponents.tsx b/src/components/rounds/mdxComponents.tsx
new file mode 100644
index 00000000..bf2d397b
--- /dev/null
+++ b/src/components/rounds/mdxComponents.tsx
@@ -0,0 +1,208 @@
+import { ReactNode } from 'react';
+import {
+ Heading,
+ Text,
+ Link,
+ UnorderedList,
+ OrderedList,
+ ListItem,
+ Box,
+ Code
+} from '@chakra-ui/react';
+
+interface MDXComponentProps {
+ children?: ReactNode;
+ id?: string;
+}
+
+interface MDXLinkProps extends MDXComponentProps {
+ href?: string;
+}
+
+/**
+ * MDX components with Chakra UI styling.
+ * IDs are added by rehype-slug plugin.
+ */
+export const mdxComponents = {
+ h1: ({ children, id }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ h2: ({ children, id }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ h3: ({ children, id }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ h4: ({ children, id }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ p: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ a: ({ href, children }: MDXLinkProps) => (
+
+ {children}
+
+ ),
+
+ ul: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ ol: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ li: ({ children }: MDXComponentProps) => (
+ {children}
+ ),
+
+ blockquote: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ code: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ pre: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ hr: () => (
+
+ ),
+
+ strong: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ ),
+
+ em: ({ children }: MDXComponentProps) => (
+
+ {children}
+
+ )
+};
diff --git a/src/constants.ts b/src/constants.ts
index 50428889..a849fd97 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -53,6 +53,15 @@ export const SIDEBAR_RFP_LINKS: SidebarLink[] = [
{ text: 'Apply', href: `${RFP_URL}/#apply` }
];
+export const OPEN_ROUNDS_URL = '/applicants/open-rounds';
+export const SIDEBAR_OPEN_ROUNDS_LINKS: SidebarLink[] = [
+ { text: 'Summary', href: `${OPEN_ROUNDS_URL}/#description` },
+ { text: 'Active Rounds', href: `${OPEN_ROUNDS_URL}/#active-rounds` }
+];
+
+// rounds
+export const ROUNDS_URL = '/rounds';
+
export const ACADEMIC_GRANTS_URL = '/academic-grants';
export const SIDEBAR_ACADEMIC_GRANTS_LINKS: SidebarLink[] = [
{ text: 'Summary', href: `${ACADEMIC_GRANTS_URL}/#introduction` },
@@ -117,7 +126,7 @@ export const REMIX_LABS_URL = 'https://remix-project.org/';
export const POWDR_LABS_URL = 'https://www.powdr.org/';
// applicants tabs
-export const APPLICANTS_TABS = ['Overview', 'Office Hours', 'Wishlist', 'RFPs'];
+export const APPLICANTS_TABS = ['Overview', 'Office Hours', 'Wishlist', 'RFPs', 'Open Rounds'];
export const APPLICANTS_TABS_MAP: TabsMap = {
[APPLICANTS_URL]: 0,
[OFFICE_HOURS_URL]: 1,
@@ -128,7 +137,8 @@ export const APPLICANTS_TABS_MAP: TabsMap = {
[WISHLIST_THANK_YOU_PAGE_URL]: 2,
[RFP_URL]: 3,
[RFP_APPLY_URL]: 3,
- [RFP_THANK_YOU_PAGE_URL]: 3
+ [RFP_THANK_YOU_PAGE_URL]: 3,
+ [OPEN_ROUNDS_URL]: 4
};
// about tabs
diff --git a/src/lib/extractHeadings.ts b/src/lib/extractHeadings.ts
new file mode 100644
index 00000000..b2b8b4bc
--- /dev/null
+++ b/src/lib/extractHeadings.ts
@@ -0,0 +1,54 @@
+import GithubSlugger from 'github-slugger';
+import type { SidebarLink } from '../types';
+
+export interface HeadingData {
+ depth: number;
+ text: string;
+ slug: string;
+}
+
+/**
+ * Extract headings from markdown content using regex.
+ * Uses github-slugger to match the IDs generated by rehype-slug.
+ */
+export const extractHeadings = (markdown: string): HeadingData[] => {
+ const slugger = new GithubSlugger();
+ const headings: HeadingData[] = [];
+
+ // Match markdown headings: ## Heading or ### Heading etc.
+ const headingRegex = /^(#{1,6})\s+(.+)$/gm;
+ let match;
+
+ while ((match = headingRegex.exec(markdown)) !== null) {
+ const depth = match[1].length;
+ const text = match[2].trim();
+ const slug = slugger.slug(text);
+
+ headings.push({ depth, text, slug });
+ }
+
+ return headings;
+};
+
+/**
+ * Convert extracted headings to sidebar links.
+ */
+export const headingsToSidebarLinks = (
+ headings: HeadingData[],
+ options: { includeDepths?: number[]; addApplyLink?: boolean } = {}
+): SidebarLink[] => {
+ const { includeDepths = [2], addApplyLink = true } = options;
+
+ const links: SidebarLink[] = headings
+ .filter(h => includeDepths.includes(h.depth))
+ .map(h => ({
+ text: h.text,
+ href: `#${h.slug}`
+ }));
+
+ if (addApplyLink) {
+ links.push({ text: 'Apply', href: '#apply' });
+ }
+
+ return links;
+};
diff --git a/src/lib/rounds/index.ts b/src/lib/rounds/index.ts
new file mode 100644
index 00000000..cf840173
--- /dev/null
+++ b/src/lib/rounds/index.ts
@@ -0,0 +1,75 @@
+import fs from 'fs';
+import path from 'path';
+import matter from 'gray-matter';
+import { Round, RoundFrontmatter } from '../../types';
+
+const ROUNDS_DIRECTORY = path.join(process.cwd(), 'content/rounds');
+
+/**
+ * Get all round slugs for static path generation
+ */
+export function getAllRoundSlugs(): string[] {
+ if (!fs.existsSync(ROUNDS_DIRECTORY)) {
+ return [];
+ }
+
+ const files = fs.readdirSync(ROUNDS_DIRECTORY);
+ return files
+ .filter(file => file.endsWith('.mdx'))
+ .map(file => file.replace(/\.mdx$/, ''));
+}
+
+/**
+ * Get a round by its slug
+ */
+export function getRoundBySlug(slug: string): Round | null {
+ const filePath = path.join(ROUNDS_DIRECTORY, `${slug}.mdx`);
+
+ if (!fs.existsSync(filePath)) {
+ return null;
+ }
+
+ const fileContents = fs.readFileSync(filePath, 'utf8');
+ const { data, content } = matter(fileContents);
+
+ return {
+ ...(data as RoundFrontmatter),
+ content
+ };
+}
+
+/**
+ * Get all active rounds
+ */
+export function getActiveRounds(): RoundFrontmatter[] {
+ const slugs = getAllRoundSlugs();
+ const rounds: RoundFrontmatter[] = [];
+
+ for (const slug of slugs) {
+ const round = getRoundBySlug(slug);
+ if (round && round.status === 'active') {
+ const { content: _, ...frontmatter } = round;
+ rounds.push(frontmatter);
+ }
+ }
+
+ return rounds;
+}
+
+/**
+ * Get all rounds (active and closed)
+ */
+export function getAllRounds(): RoundFrontmatter[] {
+ const slugs = getAllRoundSlugs();
+ const rounds: RoundFrontmatter[] = [];
+
+ for (const slug of slugs) {
+ const round = getRoundBySlug(slug);
+ if (round) {
+ const { content: _, ...frontmatter } = round;
+ rounds.push(frontmatter);
+ }
+ }
+
+ return rounds;
+}
diff --git a/src/lib/sf/index.ts b/src/lib/sf/index.ts
index 8e5ca435..cf60df57 100644
--- a/src/lib/sf/index.ts
+++ b/src/lib/sf/index.ts
@@ -1,11 +1,42 @@
import fs from 'fs';
+import path from 'path';
import jsforce from 'jsforce';
import jwt from 'jsonwebtoken';
+import matter from 'gray-matter';
import type { File } from 'formidable';
import { GrantInitiative, GrantInitiativeSalesforceRecord, GrantInitiativeType } from '../../types';
import { truncateString } from '../../utils/truncateString';
+/**
+ * Get all tags used by rounds (e.g., "AGR26")
+ * These tags should be excluded from regular RFP/Wishlist listings
+ */
+function getRoundTags(): string[] {
+ const roundsDirectory = path.join(process.cwd(), 'content/rounds');
+
+ if (!fs.existsSync(roundsDirectory)) {
+ return [];
+ }
+
+ const files = fs.readdirSync(roundsDirectory);
+ const tags: string[] = [];
+
+ for (const file of files) {
+ if (file.endsWith('.mdx')) {
+ const filePath = path.join(roundsDirectory, file);
+ const fileContents = fs.readFileSync(filePath, 'utf8');
+ const { data } = matter(fileContents);
+
+ if (data.tag) {
+ tags.push(data.tag);
+ }
+ }
+ }
+
+ return tags;
+}
+
const {
SF_PROD_LOGIN_URL,
SF_PROD_USERNAME,
@@ -108,19 +139,75 @@ const getFieldsForType = (type?: GrantInitiativeType): string => {
return baseFields;
};
+/**
+ * Transform Salesforce records into GrantInitiative objects
+ */
+const transformGrantInitiativeRecords = (
+ records: GrantInitiativeSalesforceRecord[]
+): GrantInitiative[] => {
+ return records.reduce((acc, record) => {
+ const grantInitiativeType = getGrantInitiativeType(record.RecordTypeId);
+ if (!grantInitiativeType) return acc;
+
+ const grantInitiativeItem: GrantInitiative = {
+ Id: record.Id,
+ Name: record.Name,
+ Description__c: record.Description__c,
+ Tags__c: record.Tags__c,
+ Resources__c: record.Resources__c,
+ Ecosystem_Need__c: record.Ecosystem_Need__c
+ };
+
+ if (record.Custom_URL_Slug__c) {
+ grantInitiativeItem.Custom_URL_Slug__c = record.Custom_URL_Slug__c;
+ }
+
+ if (grantInitiativeType === 'Wishlist') {
+ if (record.Out_of_Scope__c) {
+ grantInitiativeItem.Out_of_Scope__c = record.Out_of_Scope__c;
+ }
+ }
+
+ if (grantInitiativeType === 'RFP') {
+ if (record.RFP_Project_Duration__c) {
+ grantInitiativeItem.RFP_Project_Duration__c = record.RFP_Project_Duration__c;
+ }
+ if (record.RFP_HardRequirements_Long__c) {
+ grantInitiativeItem.RFP_HardRequirements_Long__c = record.RFP_HardRequirements_Long__c;
+ }
+ if (record.RFP_SoftRequirements__c) {
+ grantInitiativeItem.RFP_SoftRequirements__c = record.RFP_SoftRequirements__c;
+ }
+ if (record.RFP_Close_Date__c) {
+ grantInitiativeItem.RFP_Close_Date__c = record.RFP_Close_Date__c;
+ }
+ if (record.RFP_Open_Date__c) {
+ grantInitiativeItem.RFP_Open_Date__c = record.RFP_Open_Date__c;
+ }
+ }
+
+ acc.push(grantInitiativeItem);
+ return acc;
+ }, []);
+};
+
/**
* Get all active grant initiative items
* @param type - The type of grant initiative (Wishlist, RFP)
+ * @param options - Optional configuration
+ * @param options.excludeRoundItems - If true, excludes items that belong to grant rounds (default: true)
* @returns Promise with the grant initiative items
*/
-export function getGrantInitiativeItems(type?: GrantInitiativeType) {
+export function getGrantInitiativeItems(
+ type?: GrantInitiativeType,
+ options: { excludeRoundItems?: boolean } = { excludeRoundItems: true }
+) {
return new Promise(async (resolve, reject) => {
const conn = createConnection();
try {
await loginToSalesforce(conn);
- // TODO: Change to `Active` before deploying to production
const baseCriteria: Partial = { Status__c: 'Active' };
const criteria =
type != null
@@ -135,56 +222,63 @@ export function getGrantInitiativeItems(type?: GrantInitiativeType) {
return reject(err);
}
- const grantInitiativeItems = ret.reduce((acc, record) => {
- const grantInitiativeType = getGrantInitiativeType(record.RecordTypeId);
- if (!grantInitiativeType) return acc;
-
- const grantInitiativeItem: GrantInitiative = {
- Id: record.Id,
- Name: record.Name,
- Description__c: record.Description__c,
- Tags__c: record.Tags__c,
- Resources__c: record.Resources__c,
- Ecosystem_Need__c: record.Ecosystem_Need__c
- };
-
- if (record.Custom_URL_Slug__c) {
- grantInitiativeItem.Custom_URL_Slug__c = record.Custom_URL_Slug__c;
- }
+ let records = ret;
- if (grantInitiativeType === 'Wishlist') {
- if (record.Out_of_Scope__c) {
- grantInitiativeItem.Out_of_Scope__c = record.Out_of_Scope__c;
- }
- }
+ // Filter out items that belong to grant rounds
+ if (options.excludeRoundItems !== false) {
+ const roundTags = getRoundTags();
- if (grantInitiativeType === 'RFP') {
- if (record.RFP_Project_Duration__c) {
- grantInitiativeItem.RFP_Project_Duration__c = record.RFP_Project_Duration__c;
- }
- if (record.RFP_HardRequirements_Long__c) {
- grantInitiativeItem.RFP_HardRequirements_Long__c =
- record.RFP_HardRequirements_Long__c;
- }
- if (record.RFP_SoftRequirements__c) {
- grantInitiativeItem.RFP_SoftRequirements__c = record.RFP_SoftRequirements__c;
- }
- if (record.RFP_Close_Date__c) {
- grantInitiativeItem.RFP_Close_Date__c = record.RFP_Close_Date__c;
- }
- if (record.RFP_Open_Date__c) {
- grantInitiativeItem.RFP_Open_Date__c = record.RFP_Open_Date__c;
- }
- if (record.RFP_Project_Duration__c) {
- grantInitiativeItem.RFP_Project_Duration__c = record.RFP_Project_Duration__c;
- }
+ if (roundTags.length > 0) {
+ records = ret.filter(record => {
+ if (!record.Tags__c) return true;
+ const itemTags = record.Tags__c.split(';').map(t => t.trim());
+ // Exclude if any of the item's tags match a round tag
+ return !itemTags.some(tag => roundTags.includes(tag));
+ });
}
+ }
+
+ return resolve(transformGrantInitiativeRecords(records));
+ });
+ } catch (error) {
+ return reject(error);
+ }
+ });
+}
+
+/**
+ * Get grant initiative items filtered by tag
+ * @param tag - The tag to filter by (e.g., "AGR26")
+ * @returns Promise with the filtered grant initiative items
+ */
+export function getGrantInitiativeItemsByTag(tag: string): Promise {
+ return new Promise(async (resolve, reject) => {
+ const conn = createConnection();
+
+ try {
+ await loginToSalesforce(conn);
+
+ const criteria: Partial = {
+ Status__c: 'Active'
+ };
+
+ conn
+ .sobject('Grant_Initiative__c')
+ .find(criteria, getFieldsForType(), (err, ret) => {
+ if (err) {
+ console.error(err);
+ return reject(err);
+ }
- acc.push(grantInitiativeItem);
- return acc;
- }, []);
+ // Filter records that contain the tag in their Tags__c field
+ // Tags__c is a semicolon-separated string
+ const filteredRecords = ret.filter(record => {
+ if (!record.Tags__c) return false;
+ const tags = record.Tags__c.split(';').map(t => t.trim());
+ return tags.includes(tag);
+ });
- return resolve(grantInitiativeItems);
+ return resolve(transformGrantInitiativeRecords(filteredRecords));
});
} catch (error) {
if (!SALESFORCE_ENABLED) {
diff --git a/src/pages/applicants/open-rounds/index.tsx b/src/pages/applicants/open-rounds/index.tsx
new file mode 100644
index 00000000..3e347a6d
--- /dev/null
+++ b/src/pages/applicants/open-rounds/index.tsx
@@ -0,0 +1,142 @@
+import { Box, Flex, Stack, Text } from '@chakra-ui/react';
+import { useInView } from 'react-intersection-observer';
+import type { GetStaticProps, NextPage } from 'next';
+
+import {
+ ApplicantsSidebar,
+ PageSection,
+ PageSubheading,
+ PageText,
+ PageMetadata
+} from '../../../components/UI';
+
+import { ButtonLink } from '../../../components';
+import { SIDEBAR_OPEN_ROUNDS_LINKS, ROUNDS_URL } from '../../../constants';
+import { getActiveRounds } from '../../../lib/rounds';
+import { RoundFrontmatter } from '../../../types';
+
+interface OpenRoundsProps {
+ activeRounds: RoundFrontmatter[];
+}
+
+const RoundCard = ({ round }: { round: RoundFrontmatter }) => {
+ const { slug, name, description, endDate } = round;
+ const roundUrl = `${ROUNDS_URL}/${slug}`;
+
+ // Format the end date
+ const formattedEndDate = new Date(endDate).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+ });
+
+ return (
+
+
+
+
+ {name}
+
+
+ {description}
+
+
+ Applications close: {formattedEndDate}
+
+
+
+
+
+
+
+
+ );
+};
+
+const OpenRounds: NextPage = ({ activeRounds }) => {
+ const [ref, inView] = useInView({ threshold: 0.5 });
+ const [ref2, inView2] = useInView({ threshold: 0, initialInView: false });
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ Open Rounds
+
+
+ Grant rounds are time-limited funding opportunities focused on specific themes or
+ areas of interest. Each round has its own application deadline and selection
+ criteria. Browse active rounds below to find opportunities that match your
+ expertise.
+
+
+
+
+
+
+ Active Rounds
+
+ {activeRounds.length > 0 ? (
+
+ {activeRounds.map(round => (
+
+ ))}
+
+ ) : (
+
+ There are no active grant rounds at this time. Please check back later or
+ explore our Wishlist and RFP opportunities.
+
+ )}
+
+
+
+
+
+ >
+ );
+};
+
+export const getStaticProps: GetStaticProps = async () => {
+ const activeRounds = getActiveRounds();
+
+ return {
+ props: {
+ activeRounds
+ },
+ revalidate: 3600 // Revalidate every hour (3600 seconds)
+ };
+};
+
+export default OpenRounds;
diff --git a/src/pages/rounds/[slug].tsx b/src/pages/rounds/[slug].tsx
new file mode 100644
index 00000000..99df4188
--- /dev/null
+++ b/src/pages/rounds/[slug].tsx
@@ -0,0 +1,110 @@
+import type { GetStaticProps, GetStaticPaths, NextPage } from 'next';
+import { serialize } from 'next-mdx-remote/serialize';
+import { MDXRemoteSerializeResult } from 'next-mdx-remote';
+import { StaticImageData } from 'next/image';
+
+import rehypeSlug from 'rehype-slug';
+
+import { RoundPage } from '../../components/rounds';
+import { getAllRoundSlugs, getRoundBySlug } from '../../lib/rounds';
+import { getGrantInitiativeItemsByTag } from '../../lib/sf';
+import { extractHeadings, headingsToSidebarLinks } from '../../lib/extractHeadings';
+import { GrantInitiative, RoundFrontmatter, SidebarLink } from '../../types';
+
+// Placeholder hero images - use existing images as fallback
+import academicGrantsHero from '../../../public/images/academic-grants-hero.png';
+import academicGrantsHeroMobile from '../../../public/images/academic-grants-hero-mobile.png';
+import academicGrants25Hero from '../../../public/images/academic-grants-25-hero.jpeg';
+
+// Hero image mapping - add new rounds here as they're created
+const heroImages: Record = {
+ agr26: {
+ desktop: academicGrants25Hero,
+ mobile: academicGrantsHeroMobile
+ }
+};
+
+// Default images for rounds without specific hero images
+const defaultHeroImages = {
+ desktop: academicGrantsHero,
+ mobile: academicGrantsHeroMobile
+};
+
+interface RoundPageProps {
+ frontmatter: RoundFrontmatter;
+ mdxSource: MDXRemoteSerializeResult;
+ items: GrantInitiative[];
+ sidebarLinks: SidebarLink[];
+}
+
+const RoundPageRoute: NextPage = ({
+ frontmatter,
+ mdxSource,
+ items,
+ sidebarLinks
+}) => {
+ const images = heroImages[frontmatter.slug] || defaultHeroImages;
+
+ return (
+
+ );
+};
+
+export const getStaticPaths: GetStaticPaths = async () => {
+ const slugs = getAllRoundSlugs();
+
+ return {
+ paths: slugs.map(slug => ({
+ params: { slug }
+ })),
+ fallback: false
+ };
+};
+
+export const getStaticProps: GetStaticProps = async ({ params }) => {
+ const slug = params?.slug as string;
+ const round = getRoundBySlug(slug);
+
+ if (!round) {
+ return {
+ notFound: true
+ };
+ }
+
+ const { content, ...frontmatter } = round;
+
+ // Extract headings from markdown content
+ const headings = extractHeadings(content);
+ const sidebarLinks = headingsToSidebarLinks(headings, {
+ includeDepths: [2, 3],
+ addApplyLink: true
+ });
+
+ // Serialize MDX with rehype-slug to add IDs to headings
+ const mdxSource = await serialize(content, {
+ mdxOptions: {
+ rehypePlugins: [rehypeSlug]
+ }
+ });
+
+ // Fetch items from Salesforce filtered by tag
+ const items = await getGrantInitiativeItemsByTag(frontmatter.tag);
+
+ return {
+ props: {
+ frontmatter,
+ mdxSource,
+ items,
+ sidebarLinks
+ },
+ revalidate: 3600 // Revalidate every hour
+ };
+};
+
+export default RoundPageRoute;
diff --git a/src/theme/foundations/colors.ts b/src/theme/foundations/colors.ts
index 50d833bf..820ee2c7 100644
--- a/src/theme/foundations/colors.ts
+++ b/src/theme/foundations/colors.ts
@@ -163,6 +163,13 @@ export const colors = {
start: '#e078611a',
end: '#e06361'
}
+ },
+ academicGrants2026Hero: {
+ titleWhiteBox: 'rgba(255, 255, 255, 0.6)',
+ bgGradient: {
+ start: '#cc9eb0',
+ end: 'rgba(235, 209, 251, 0)'
+ }
}
}
};
diff --git a/src/types.ts b/src/types.ts
index c02f5ea1..87e2f484 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -516,3 +516,21 @@ export interface GrantInitiative {
RFP_SoftRequirements__c?: string;
Custom_URL_Slug__c?: string;
}
+
+export type RoundStatus = 'active' | 'closed';
+
+export interface RoundFrontmatter {
+ slug: string;
+ name: string;
+ description: string;
+ status: RoundStatus;
+ tag: string;
+ heroImage: string;
+ colorBrand: string;
+ startDate: string;
+ endDate: string;
+}
+
+export interface Round extends RoundFrontmatter {
+ content: string;
+}