diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1bfe3a2e..1c87a2fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -595,6 +595,64 @@ importers: specifier: ^5 version: 5.6.3 + samples/next-mdx-static-import: + dependencies: + '@content-collections/core': + specifier: 0.7.3 + version: link:../../packages/core + '@content-collections/next': + specifier: 0.2.4 + version: link:../../packages/next + '@content-collections/sample-theme': + specifier: 0.1.0 + version: link:../../utils/sample-theme + '@mdx-js/loader': + specifier: ^3.1.0 + version: 3.1.0 + '@mdx-js/react': + specifier: ^3.1.0 + version: 3.1.0(@types/react@18.3.3)(react@18.3.1) + '@next/mdx': + specifier: 14.2.20 + version: 14.2.20(@mdx-js/loader@3.1.0)(@mdx-js/react@3.1.0) + '@types/mdx': + specifier: ^2.0.13 + version: 2.0.13 + next: + specifier: 14.2.20 + version: 14.2.20(@playwright/test@1.47.0)(react-dom@18.3.1)(react@18.3.1) + react: + specifier: ^18 + version: 18.3.1 + react-dom: + specifier: ^18 + version: 18.3.1(react@18.3.1) + devDependencies: + '@types/node': + specifier: ^20 + version: 20.14.9 + '@types/react': + specifier: ^18.3.3 + version: 18.3.3 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 + eslint: + specifier: ^8 + version: 8.57.0 + eslint-config-next: + specifier: 14.2.20 + version: 14.2.20(eslint@8.57.0)(typescript@5.7.2) + remark-frontmatter: + specifier: ^5.0.0 + version: 5.0.0 + remark-mdx-frontmatter: + specifier: ^4.0.0 + version: 4.0.0 + typescript: + specifier: ^5 + version: 5.7.2 + samples/next-pages: dependencies: '@content-collections/core': @@ -4012,12 +4070,38 @@ packages: /@next/env@14.2.15: resolution: {integrity: sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ==} + /@next/env@14.2.20: + resolution: {integrity: sha512-JfDpuOCB0UBKlEgEy/H6qcBSzHimn/YWjUHzKl1jMeUO+QVRdzmTTl8gFJaNO87c8DXmVKhFCtwxQ9acqB3+Pw==} + dev: false + /@next/eslint-plugin-next@14.2.15: resolution: {integrity: sha512-pKU0iqKRBlFB/ocOI1Ip2CkKePZpYpnw5bEItEkuZ/Nr9FQP1+p7VDWr4VfOdff4i9bFmrOaeaU1bFEyAcxiMQ==} dependencies: glob: 10.3.10 dev: true + /@next/eslint-plugin-next@14.2.20: + resolution: {integrity: sha512-T0JRi706KLbvR1Uc46t56VtawbhR/igdBagzOrA7G+vv4rvjwnlu/Y4/Iq6X9TDVj5UZjyot4lUdkNd3V2kLhw==} + dependencies: + glob: 10.3.10 + dev: true + + /@next/mdx@14.2.20(@mdx-js/loader@3.1.0)(@mdx-js/react@3.1.0): + resolution: {integrity: sha512-DBO56cbTq5WnW8USiFQY/uwdz4/8/rzxRBhJYMGPUOs2Kex1ZmooMcgM+5yjEGLr3zI3miVG/G+U1HeAyW0V/g==} + peerDependencies: + '@mdx-js/loader': '>=0.15.0' + '@mdx-js/react': '>=0.15.0' + peerDependenciesMeta: + '@mdx-js/loader': + optional: true + '@mdx-js/react': + optional: true + dependencies: + '@mdx-js/loader': 3.1.0 + '@mdx-js/react': 3.1.0(@types/react@18.3.3)(react@18.3.1) + source-map: 0.7.4 + dev: false + /@next/mdx@15.0.3(@mdx-js/loader@3.1.0)(@mdx-js/react@3.1.0): resolution: {integrity: sha512-EwCJKDeJqfbHbsS7rIdWpKDOZsOPsif9AX4PaIhy5ghSMsZvi+/vIZVc07pZT7BdwCIoL9XM1KZMd/vzxCxF5A==} peerDependencies: @@ -4042,6 +4126,15 @@ packages: requiresBuild: true optional: true + /@next/swc-darwin-arm64@14.2.20: + resolution: {integrity: sha512-WDfq7bmROa5cIlk6ZNonNdVhKmbCv38XteVFYsxea1vDJt3SnYGgxLGMTXQNfs5OkFvAhmfKKrwe7Y0Hs+rWOg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@next/swc-darwin-x64@14.2.15: resolution: {integrity: sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg==} engines: {node: '>= 10'} @@ -4050,6 +4143,15 @@ packages: requiresBuild: true optional: true + /@next/swc-darwin-x64@14.2.20: + resolution: {integrity: sha512-XIQlC+NAmJPfa2hruLvr1H1QJJeqOTDV+v7tl/jIdoFvqhoihvSNykLU/G6NMgoeo+e/H7p/VeWSOvMUHKtTIg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-arm64-gnu@14.2.15: resolution: {integrity: sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw==} engines: {node: '>= 10'} @@ -4058,6 +4160,15 @@ packages: requiresBuild: true optional: true + /@next/swc-linux-arm64-gnu@14.2.20: + resolution: {integrity: sha512-pnzBrHTPXIMm5QX3QC8XeMkpVuoAYOmyfsO4VlPn+0NrHraNuWjdhe+3xLq01xR++iCvX+uoeZmJDKcOxI201Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-arm64-musl@14.2.15: resolution: {integrity: sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ==} engines: {node: '>= 10'} @@ -4066,6 +4177,15 @@ packages: requiresBuild: true optional: true + /@next/swc-linux-arm64-musl@14.2.20: + resolution: {integrity: sha512-WhJJAFpi6yqmUx1momewSdcm/iRXFQS0HU2qlUGlGE/+98eu7JWLD5AAaP/tkK1mudS/rH2f9E3WCEF2iYDydQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-x64-gnu@14.2.15: resolution: {integrity: sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA==} engines: {node: '>= 10'} @@ -4074,6 +4194,15 @@ packages: requiresBuild: true optional: true + /@next/swc-linux-x64-gnu@14.2.20: + resolution: {integrity: sha512-ao5HCbw9+iG1Kxm8XsGa3X174Ahn17mSYBQlY6VGsdsYDAbz/ZP13wSLfvlYoIDn1Ger6uYA+yt/3Y9KTIupRg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-x64-musl@14.2.15: resolution: {integrity: sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ==} engines: {node: '>= 10'} @@ -4082,6 +4211,15 @@ packages: requiresBuild: true optional: true + /@next/swc-linux-x64-musl@14.2.20: + resolution: {integrity: sha512-CXm/kpnltKTT7945np6Td3w7shj/92TMRPyI/VvveFe8+YE+/YOJ5hyAWK5rpx711XO1jBCgXl211TWaxOtkaA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-win32-arm64-msvc@14.2.15: resolution: {integrity: sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g==} engines: {node: '>= 10'} @@ -4090,6 +4228,15 @@ packages: requiresBuild: true optional: true + /@next/swc-win32-arm64-msvc@14.2.20: + resolution: {integrity: sha512-upJn2HGQgKNDbXVfIgmqT2BN8f3z/mX8ddoyi1I565FHbfowVK5pnMEwauvLvaJf4iijvuKq3kw/b6E9oIVRWA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@next/swc-win32-ia32-msvc@14.2.15: resolution: {integrity: sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ==} engines: {node: '>= 10'} @@ -4098,6 +4245,15 @@ packages: requiresBuild: true optional: true + /@next/swc-win32-ia32-msvc@14.2.20: + resolution: {integrity: sha512-igQW/JWciTGJwj3G1ipalD2V20Xfx3ywQy17IV0ciOUBbFhNfyU1DILWsTi32c8KmqgIDviUEulW/yPb2FF90w==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@next/swc-win32-x64-msvc@14.2.15: resolution: {integrity: sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g==} engines: {node: '>= 10'} @@ -4106,6 +4262,15 @@ packages: requiresBuild: true optional: true + /@next/swc-win32-x64-msvc@14.2.20: + resolution: {integrity: sha512-AFmqeLW6LtxeFTuoB+MXFeM5fm5052i3MU6xD0WzJDOwku6SkZaxb1bxjBaRC8uNqTRTSPl0yMFtjNowIVI67w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -6562,7 +6727,7 @@ packages: resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} dependencies: '@swc/counter': 0.1.3 - tslib: 2.7.0 + tslib: 2.8.1 /@tailwindcss/typography@0.5.14(tailwindcss@3.4.4): resolution: {integrity: sha512-ZvOCjUbsJBjL9CxQBn+VEnFpouzuKhxh2dH8xMIWHILL+HfOYtlAkWcyoon8LlzE53d2Yo6YO6pahKKNW3q1YQ==} @@ -6926,6 +7091,35 @@ packages: - supports-color dev: true + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.4 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + semver: 7.6.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5): resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} @@ -6989,6 +7183,27 @@ packages: - supports-color dev: true + /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.4 + eslint: 8.57.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@6.21.0: resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -7065,6 +7280,26 @@ packages: - supports-color dev: true + /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + debug: 4.3.7 + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types@6.21.0: resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -7141,6 +7376,28 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.7.2): + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.7 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/typescript-estree@8.16.0(typescript@5.5.4): resolution: {integrity: sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -7220,6 +7477,25 @@ packages: - typescript dev: true + /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) + eslint: 8.57.0 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/utils@8.16.0(eslint@8.57.0)(typescript@5.5.4): resolution: {integrity: sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9713,6 +9989,32 @@ packages: - supports-color dev: true + /eslint-config-next@14.2.20(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-gHBvp4RDd51DAaDco7KiWFy731EwcItkDtGUaZH1EUXEnHCzsVRjMceT+b8aThjMLjOScz6Q27MGlePASvK4Aw==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@next/eslint-plugin-next': 14.2.20 + '@rushstack/eslint-patch': 1.10.2 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) + eslint-plugin-react: 7.34.1(eslint@8.57.0) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) + typescript: 5.7.2 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - supports-color + dev: true + /eslint-config-prettier@9.1.0(eslint@8.57.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true @@ -9745,7 +10047,7 @@ packages: eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0) fast-glob: 3.3.2 - get-tsconfig: 4.7.4 + get-tsconfig: 4.8.1 is-core-module: 2.13.1 is-glob: 4.0.3 transitivePeerDependencies: @@ -13695,6 +13997,49 @@ packages: - '@babel/core' - babel-plugin-macros + /next@14.2.20(@playwright/test@1.47.0)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-yPvIiWsiyVYqJlSQxwmzMIReXn5HxFNq4+tlVQ812N1FbvhmE+fDpIAD7bcS2mGYQwPJ5vAsQouyme2eKsxaug==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true + dependencies: + '@next/env': 14.2.20 + '@playwright/test': 1.47.0 + '@swc/helpers': 0.5.5 + busboy: 1.6.0 + caniuse-lite: 1.0.30001669 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + styled-jsx: 5.1.1(react@18.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.20 + '@next/swc-darwin-x64': 14.2.20 + '@next/swc-linux-arm64-gnu': 14.2.20 + '@next/swc-linux-arm64-musl': 14.2.20 + '@next/swc-linux-x64-gnu': 14.2.20 + '@next/swc-linux-x64-musl': 14.2.20 + '@next/swc-win32-arm64-msvc': 14.2.20 + '@next/swc-win32-ia32-msvc': 14.2.20 + '@next/swc-win32-x64-msvc': 14.2.20 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + dev: false + /nitropack@2.9.6(@opentelemetry/api@1.8.0): resolution: {integrity: sha512-HP2PE0dREcDIBVkL8Zm6eVyrDd10/GI9hTL00PHvjUM8I9Y/2cv73wRDmxNyInfrx/CJKHATb2U/pQrqpzJyXA==} engines: {node: ^16.11.0 || >=17.0.0} @@ -14633,7 +14978,7 @@ packages: engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 - picocolors: 1.1.0 + picocolors: 1.1.1 source-map-js: 1.2.1 /postcss@8.4.45: @@ -16757,6 +17102,15 @@ packages: typescript: 5.6.3 dev: true + /ts-api-utils@1.3.0(typescript@5.7.2): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.7.2 + dev: true + /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -16798,6 +17152,7 @@ packages: /tslib@2.7.0: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} requiresBuild: true + dev: false /tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} diff --git a/samples/next-mdx-static-import/.eslintrc.json b/samples/next-mdx-static-import/.eslintrc.json new file mode 100644 index 00000000..bffb357a --- /dev/null +++ b/samples/next-mdx-static-import/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/samples/next-mdx-static-import/.gitignore b/samples/next-mdx-static-import/.gitignore new file mode 100644 index 00000000..fd3dbb57 --- /dev/null +++ b/samples/next-mdx-static-import/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/samples/next-mdx-static-import/README.md b/samples/next-mdx-static-import/README.md new file mode 100644 index 00000000..1641e2ae --- /dev/null +++ b/samples/next-mdx-static-import/README.md @@ -0,0 +1,104 @@ +--- +title: Next.js MDX Static Import +description: Let Next.js compile MDX, and simply import the files +tags: + - next.js + - react + - rsc + - mdx +adapter: next +--- + + + The method used in this sample does not currently work with turborepo. + + +## Installation + +- Follow the instructions to [configure MDX routes in your Next.js project](https://nextjs.org/docs/app/building-your-application/configuring/mdx) +- Install Content Collections: [Next.js Quick Start](https://www.content-collections.dev/docs/quickstart/next) + +## Configuration + +Configure Content Collections that it discover the MDX files, but we exclude the content from the generated files e.g.: + +```ts +import { defineCollection, defineConfig } from "@content-collections/core"; + +const posts = defineCollection({ + name: "posts", + directory: "./content/posts", + include: "*.mdx", + schema: (z) => ({ + title: z.string(), + }), + transform: ({ content: _, ...post }) => { + return post; + }, +}); + +export default defineConfig({ + collections: [posts], +}); +``` + +We have to tell Next.js to remove the frontmatter from the MDX files during the compilation because the frontmatter is handled by Content Collections. For this, we have to configure the remark plugins remarkFrontmatter and remarkMdxFrontmatter in the Next.js configuration, e.g.: + +```js +import { withContentCollections } from "@content-collections/next"; +import createMDX from "@next/mdx"; +import remarkFrontmatter from 'remark-frontmatter' +import remarkMdxFrontmatter from 'remark-mdx-frontmatter' + +/** @type {import('next').NextConfig} */ +const nextConfig = { + pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"], +}; + +const withMDX = createMDX({ + options: { + remarkPlugins: [remarkFrontmatter,remarkMdxFrontmatter], + rehypePlugins: [], + }, +}); + +export default withContentCollections(withMDX(nextConfig)); +``` + +## Usage + +Now we can use the generated `allPosts` collections as usual: + +```tsx + +``` + +But when we want to render the content of a post, we can use a dynamic import to let Next.js compile the MDX file for us: + +```tsx +export default async function Post({ params: { slug } }: Props) { + const post = allPosts.find((post) => post.slug === slug); + if (!post) { + return notFound(); + } + + const { default: Content } = await import(`../../content/posts/${post.slug}.mdx`); + + return ( +
+

{post.title}

+
+ +
+
+ ); +} +``` diff --git a/samples/next-mdx-static-import/app/layout.tsx b/samples/next-mdx-static-import/app/layout.tsx new file mode 100644 index 00000000..5fbe2d38 --- /dev/null +++ b/samples/next-mdx-static-import/app/layout.tsx @@ -0,0 +1,36 @@ +import type { Metadata } from "next"; +import "@content-collections/sample-theme/sample.css"; +import Link from "next/link"; + +export const metadata: Metadata = { + title: "Content Collections", + description: "Using Content Collections with Next.js", +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + +
+

ContentCrafter Inc.

+

+ From Worldly Wonders to Polished Perfection – Crafting Content That + Captivates and Converts. +

+ +
+
{children}
+ + + + ); +} diff --git a/samples/next-mdx-static-import/app/page.tsx b/samples/next-mdx-static-import/app/page.tsx new file mode 100644 index 00000000..2b57ce52 --- /dev/null +++ b/samples/next-mdx-static-import/app/page.tsx @@ -0,0 +1,21 @@ +import { allPosts } from "content-collections"; +import Link from "next/link"; + +export default function Page() { + return ( +
+

Posts

+
+ {allPosts.map((post) => ( + +
+

{post.title}

+ +
+

{post.summary}

+ + ))} +
+
+ ); +} diff --git a/samples/next-mdx-static-import/app/posts/[slug]/page.tsx b/samples/next-mdx-static-import/app/posts/[slug]/page.tsx new file mode 100644 index 00000000..40ab714d --- /dev/null +++ b/samples/next-mdx-static-import/app/posts/[slug]/page.tsx @@ -0,0 +1,32 @@ +import { allPosts } from "content-collections"; +import { notFound } from "next/navigation"; + +type Props = { + params: { + slug: string; + }; +}; + +export default async function Post({ params: { slug } }: Props) { + const post = allPosts.find((post) => post.slug === slug); + if (!post) { + return notFound(); + } + + const MdxContent = post.mdxContent; + + return ( +
+
+

{post.title}

+
+
+ +
+ +
+ ); +} diff --git a/samples/next-mdx-static-import/components/Internship.tsx b/samples/next-mdx-static-import/components/Internship.tsx new file mode 100644 index 00000000..65270041 --- /dev/null +++ b/samples/next-mdx-static-import/components/Internship.tsx @@ -0,0 +1,16 @@ +type Props = { + children: React.ReactNode; +}; + +export function Internship({ children }: Props) { + return ( +
+

Internship at ContentCrafter Inc.

+

+ Are you creative and passionate about writing? ContentCrafter Inc. is + looking for motivated interns to support our team! +

+

Interested? Send your application to contact@contentcrafter.com.

+
+ ); +} diff --git a/samples/next-mdx-static-import/content-collections.ts b/samples/next-mdx-static-import/content-collections.ts new file mode 100644 index 00000000..1692e151 --- /dev/null +++ b/samples/next-mdx-static-import/content-collections.ts @@ -0,0 +1,31 @@ +import { + createDefaultImport, + defineCollection, + defineConfig, +} from "@content-collections/core"; +import { MDXContent } from "mdx/types"; + +const posts = defineCollection({ + name: "posts", + directory: "./content/posts", + include: "*.mdx", + schema: (z) => ({ + title: z.string(), + summary: z.string(), + date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/), + author: z.string(), + }), + transform: ({ content: _, _meta, ...post }) => { + const mdxContent = createDefaultImport(`@/content/posts/${_meta.filePath}`); + const slug = _meta.path; + return { + ...post, + mdxContent, + slug, + }; + }, +}); + +export default defineConfig({ + collections: [posts], +}); diff --git a/samples/next-mdx-static-import/content/posts/how-a-sloth-revolutionized-our-deadline-management.mdx b/samples/next-mdx-static-import/content/posts/how-a-sloth-revolutionized-our-deadline-management.mdx new file mode 100644 index 00000000..62e0afea --- /dev/null +++ b/samples/next-mdx-static-import/content/posts/how-a-sloth-revolutionized-our-deadline-management.mdx @@ -0,0 +1,40 @@ +--- +title: "How a Sloth Revolutionized Our Deadline Management" +summary: "A chance encounter with a three-toed sloth named Fernando in Costa Rica leads ContentCrafter Inc. to revolutionize their approach to content creation. Through observing Fernando's methodical movements, the team learns valuable lessons about purposeful work, leading to improved quality and efficiency across all departments, proving that sometimes slowing down is the key to better results." +date: 2024-03-15 +author: "Alexandra Winters" +--- + +import { Internship } from "@/components/Internship"; + + + +Our content creation journey at ContentCrafter Inc. has always been filled with unexpected twists and turns, but nothing quite prepared us for the day our entire workflow philosophy would be transformed by an unlikely productivity guru – a three-toed sloth named Fernando. + +## When Slow and Steady Wins the Race + +It all started when our collector, Sarah, ventured deep into the Costa Rican rainforest in search of inspiration for a client's eco-tourism campaign. Armed with her trusty camera and an overly ambitious shot list, she was determined to capture the perfect moments of wildlife in action. That's when she encountered Fernando, peacefully hanging from a branch, moving with such deliberate grace that it made our usual rushing around seem almost comical. + +"I was frantically checking my watch, worried about missing my next appointment," Sarah recalls, chuckling. "Meanwhile, Fernando just gave me this knowing look, took three minutes to blink, and somehow made me question everything I knew about time management." + +## The Great Validation Revelation + +When Sarah's footage reached our validation team, something extraordinary happened. Our usually fast-paced validators, known for their lightning-quick fact-checking abilities, found themselves oddly mesmerized by Fernando's methodical movements. + +"There was something almost hypnotic about watching Fernando navigate his branch," explains Marcus, our lead validator. "He took fifteen minutes to reach for a leaf, but every movement was purposeful, efficient, and – most importantly – error-free. It was like watching a masterclass in quality control." + +The team started implementing what they jokingly called "The Fernando Method" – a deliberate, mindful approach to content validation that, surprisingly, resulted in fewer revision requests and higher quality outputs. + +## The Transformation Station + +Our transformers initially scoffed at the idea of slowing down their creative process. After all, creativity strikes like lightning, right? Wrong, as Fernando would have very slowly told us. + +"We used to pride ourselves on our rapid-fire brainstorming sessions," admits Jessica, our senior transformer. "But after studying Fernando's footage, we realized that some of our best ideas needed time to marinate. We started taking 'sloth breaks' – five-minute periods of slow, deliberate thinking between ideation sessions." + +The results were astonishing. Our content became richer, more nuanced, and ironically, we started meeting deadlines more consistently. Turns out, panic-induced creativity wasn't all it was cracked up to be. + +## The Sloth Revolution + +What began as a simple wildlife filming assignment evolved into a company-wide philosophy. We installed a large photo of Fernando in our main conference room, complete with a caption that reads "What Would Fernando Do?" It serves as a reminder that sometimes the path to efficiency isn't about moving faster, but about moving more purposefully. + +Our clients noticed the difference too. One even commented, "There's something different about your content lately – it feels more... thoughtful." Little did they know it was all thanks to a sloth who never rushed a single moment of his life. diff --git a/samples/next-mdx-static-import/content/posts/my-gps-was-possessed-by-a-mischievous-mountain-goat.mdx b/samples/next-mdx-static-import/content/posts/my-gps-was-possessed-by-a-mischievous-mountain-goat.mdx new file mode 100644 index 00000000..ba3d783a --- /dev/null +++ b/samples/next-mdx-static-import/content/posts/my-gps-was-possessed-by-a-mischievous-mountain-goat.mdx @@ -0,0 +1,36 @@ +--- +title: My GPS Was Possessed By A Mischievous Mountain Goat +summary: A hilarious tale of ContentCrafter's collection team's misadventures in the Swiss Alps, where a tech-savvy mountain goat repeatedly altered their GPS coordinates, leading to an unexpected discovery of an ancient cheese-making tradition. The story showcases how sometimes the best content comes from embracing the unexpected, even if it means following a goat's digital breadcrumbs. +date: 2023-09-15 +author: Alexandra Winters +--- + +The Swiss Alps are magnificent, they said. The GPS will guide you perfectly, they said. Nobody mentioned anything about tech-savvy mountain goats with a peculiar sense of humor. But here at ContentCrafter Inc., we've learned that the best stories often come from the most unexpected sources – even if that source happens to be a four-legged prankster with a mysterious ability to hack navigation systems. + +## When Technology Meets Nature's Comedians + +It all started on a crisp morning in the Bernese Oberland. Our collection team, armed with the latest GPS technology and enough equipment to document a small expedition, set out to gather content about traditional Swiss cheese-making techniques. Little did we know that our carefully planned route would soon be hijacked by what we now affectionately call "The Algorithm Goat." + +Every time we checked our GPS coordinates, they somehow pointed us to seemingly random locations. At first, we blamed it on satellite interference or equipment malfunction. But then we noticed a pattern – and a suspicious-looking goat that appeared at every wrong turn, sporting what could only be described as a smirk. + +## The Great Validation Debate + +Back at headquarters, our validation team had their hands full with this one. "How do we verify that a goat manipulated our GPS?" demanded Sarah from Quality Control, peering through her reading glasses at hours of footage. The evidence was circumstantial but compelling: every time the goat appeared in frame, our coordinates shifted to point toward ancient cheese-making locations we hadn't even known existed. + +"Maybe it's trying to help?" suggested Mike, our newest validator, earning himself eye-rolls from the veteran team members. But as they dug deeper into the data, they couldn't deny that our furry friend had led us to some extraordinary discoveries. + +## Transforming Chaos into Content Gold + +Our transformation team couldn't believe their luck. What started as a straightforward piece about traditional cheese-making evolved into something far more engaging. "We've got a viral story on our hands," declared Rachel, our lead content transformer, her eyes gleaming with excitement. "A mountain goat with a PhD in GPS manipulation? That's pure content gold!" + +The team worked their magic, weaving together the technical mishaps, the goat's mysterious appearances, and the incredible traditional cheese-making locations we discovered along the way. They created an interactive map showing our intended route versus the "goat-guided tour," complete with cheese-themed markers and tiny digital goat footprints. + +## The Unexpected Success + +The finished piece became one of our most successful content campaigns ever. It turns out that people love stories about traditional craftsmanship, especially when they're delivered through the lens of a possibly tech-savvy mountain goat. Our client, a major Swiss tourism board, reported a significant increase in interest in their artisanal cheese tours. + +As for our four-legged friend? Legend has it that on quiet mountain mornings, hikers still report mysterious GPS glitches, always accompanied by the distant sound of bleating and what sounds suspiciously like digital laughter. + +Here at ContentCrafter Inc., we've learned to embrace the unexpected. Sometimes the best stories find us, even if they have to hack our GPS to do it. And if you ever find yourself in the Swiss Alps with a malfunctioning navigation system, look around – you might just be in the presence of our favorite content contributor. + +Just remember to pack extra batteries. And maybe some cheese. You never know when you might need to bribe a tech-savvy goat. diff --git a/samples/next-mdx-static-import/mdx-components.tsx b/samples/next-mdx-static-import/mdx-components.tsx new file mode 100644 index 00000000..9ff72291 --- /dev/null +++ b/samples/next-mdx-static-import/mdx-components.tsx @@ -0,0 +1,7 @@ +import type { MDXComponents } from "mdx/types"; + +export function useMDXComponents(components: MDXComponents): MDXComponents { + return { + ...components, + }; +} diff --git a/samples/next-mdx-static-import/next.config.mjs b/samples/next-mdx-static-import/next.config.mjs new file mode 100644 index 00000000..78150aaf --- /dev/null +++ b/samples/next-mdx-static-import/next.config.mjs @@ -0,0 +1,16 @@ +import { withContentCollections } from "@content-collections/next"; +import createMDX from "@next/mdx"; +import remarkFrontmatter from "remark-frontmatter"; +import remarkMdxFrontmatter from "remark-mdx-frontmatter"; + +/** @type {import('next').NextConfig} */ +const nextConfig = {}; + +const withMDX = createMDX({ + options: { + remarkPlugins: [remarkFrontmatter, remarkMdxFrontmatter], + rehypePlugins: [], + }, +}); + +export default withContentCollections(withMDX(nextConfig)); diff --git a/samples/next-mdx-static-import/package.json b/samples/next-mdx-static-import/package.json new file mode 100644 index 00000000..f0c74050 --- /dev/null +++ b/samples/next-mdx-static-import/package.json @@ -0,0 +1,32 @@ +{ + "name": "samples-next-mdx-static-import", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "lint": "next lint", + "test": "playwright test" + }, + "dependencies": { + "@content-collections/core": "0.7.3", + "@content-collections/next": "0.2.4", + "@content-collections/sample-theme": "0.1.0", + "@mdx-js/loader": "^3.1.0", + "@mdx-js/react": "^3.1.0", + "@next/mdx": "14.2.20", + "@types/mdx": "^2.0.13", + "next": "14.2.20", + "react": "^18", + "react-dom": "^18" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "eslint": "^8", + "eslint-config-next": "14.2.20", + "remark-frontmatter": "^5.0.0", + "remark-mdx-frontmatter": "^4.0.0", + "typescript": "^5" + } +} diff --git a/samples/next-mdx-static-import/playwright.config.ts b/samples/next-mdx-static-import/playwright.config.ts new file mode 100644 index 00000000..e533bffc --- /dev/null +++ b/samples/next-mdx-static-import/playwright.config.ts @@ -0,0 +1,47 @@ +import { defineConfig, devices } from "@playwright/test"; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: "./tests", + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: "html", + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: "http://localhost:3003", + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: "on-first-retry", + }, + + /** one browser is enough to test if out collections work */ + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: "pnpm run dev --port=3003", + url: "http://localhost:3003", + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/samples/next-mdx-static-import/tests/collection.spec.ts b/samples/next-mdx-static-import/tests/collection.spec.ts new file mode 100644 index 00000000..c1b2c9d0 --- /dev/null +++ b/samples/next-mdx-static-import/tests/collection.spec.ts @@ -0,0 +1,40 @@ +import { expect, test } from "@playwright/test"; + +test.beforeEach(async ({ page }) => { + await page.goto("/"); +}); + +test("should list available posts", async ({ page }) => { + await expect( + page.getByRole("heading", { + name: "How a Sloth Revolutionized Our Deadline Management", + }), + ).toBeVisible(); + await expect( + page.getByRole("heading", { + name: "My GPS Was Possessed By A Mischievous Mountain Goat", + }), + ).toBeVisible(); +}); + +test("should render post content", async ({ page }) => { + const link = await page.getByRole("heading", { + name: "How a Sloth Revolutionized Our Deadline Management", + }); + await link.click(); + + await expect( + page.getByRole("heading", { name: "The Great Validation Revelation" }), + ).toBeVisible(); +}); + +test("should render imported component", async ({ page }) => { + const link = await page.getByRole("heading", { + name: "How a Sloth Revolutionized Our Deadline Management", + }); + await link.click(); + + await expect( + page.getByRole("heading", { name: "Internship at ContentCrafter Inc." }), + ).toBeVisible(); +}); diff --git a/samples/next-mdx-static-import/tsconfig.json b/samples/next-mdx-static-import/tsconfig.json new file mode 100644 index 00000000..b4393d35 --- /dev/null +++ b/samples/next-mdx-static-import/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"], + "content-collections": ["./.content-collections/generated"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +}