diff --git a/package-lock.json b/package-lock.json index e091273..a006c2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -954,6 +953,14 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@heroicons/react": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.5.tgz", + "integrity": "sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA==", + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -986,7 +993,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -1004,7 +1010,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1017,7 +1022,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -1110,7 +1114,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -1125,7 +1128,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1135,7 +1137,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1145,14 +1146,12 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1191,11 +1190,150 @@ "react": ">=16" } }, + "node_modules/@next/env": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.11.tgz", + "integrity": "sha512-HYsQRSIXwiNqvzzYThrBwq6RhXo3E0n8j8nQnAs8i4fCEo2Zf/3eS0IiRA8XnRg9Ha0YnpkyJZIZg1qEwemrHw==" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.11.tgz", + "integrity": "sha512-eiY9u7wEJZWp/Pga07Qy3ZmNEfALmmSS1HtsJF3y1QEyaExu7boENz11fWqDmZ3uvcyAxCMhTrA1jfVxITQW8g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.11.tgz", + "integrity": "sha512-lnB0zYCld4yE0IX3ANrVMmtAbziBb7MYekcmR6iE9bujmgERl6+FK+b0MBq0pl304lYe7zO4yxJus9H/Af8jbg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.11.tgz", + "integrity": "sha512-Ulo9TZVocYmUAtzvZ7FfldtwUoQY0+9z3BiXZCLSUwU2bp7GqHA7/bqrfsArDlUb2xeGwn3ZuBbKtNK8TR0A8w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.11.tgz", + "integrity": "sha512-fH377DnKGyUnkWlmUpFF1T90m0dADBfK11dF8sOQkiELF9M+YwDRCGe8ZyDzvQcUd20Rr5U7vpZRrAxKwd3Rzg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.11.tgz", + "integrity": "sha512-a0TH4ZZp4NS0LgXP/488kgvWelNpwfgGTUCDXVhPGH6pInb7yIYNgM4kmNWOxBFt+TIuOH6Pi9NnGG4XWFUyXQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.11.tgz", + "integrity": "sha512-DYYZcO4Uir2gZxA4D2JcOAKVs8ZxbOFYPpXSVIgeoQbREbeEHxysVsg3nY4FrQy51e5opxt5mOHl/LzIyZBoKA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.11.tgz", + "integrity": "sha512-PwqHeKG3/kKfPpM6of1B9UJ+Er6ySUy59PeFu0Un0LBzJTRKKAg2V6J60Yqzp99m55mLa+YTbU6xj61ImTv9mg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.11.tgz", + "integrity": "sha512-0U7PWMnOYIvM74GY6rbH6w7v+vNPDVH1gUhlwHpfInJnNe5LkmUZqhp7FNWeNa5wbVgRcRi1F1cyxp4dmeLLvA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.11.tgz", + "integrity": "sha512-gQpS7mcgovWoaTG1FbS5/ojF7CGfql1Q0ZLsMrhcsi2Sr9HEqsUZ70MPJyaYBXbk6iEAP7UXMD9HC8KY1qNwvA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1209,7 +1347,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -1219,7 +1356,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -1246,7 +1382,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -2364,6 +2499,37 @@ "storybook": "^8.3.0" } }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz", + "integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@testing-library/dom": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", @@ -2648,6 +2814,14 @@ "@types/node": "*" } }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/doctrine": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", @@ -2666,9 +2840,16 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true, "license": "MIT" }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", @@ -2717,7 +2898,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "*" @@ -2756,6 +2936,14 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/mdx": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", @@ -2777,6 +2965,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, "node_modules/@types/node": { "version": "20.16.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", @@ -2807,7 +3000,6 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true, "license": "MIT" }, "node_modules/@types/qs": { @@ -2828,7 +3020,6 @@ "version": "18.3.5", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -2896,7 +3087,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true, "license": "MIT" }, "node_modules/@types/uuid": { @@ -3152,7 +3342,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true, "license": "ISC" }, "node_modules/@vitejs/plugin-react": { @@ -3435,7 +3624,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3458,14 +3646,12 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -3479,7 +3665,6 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -3568,11 +3753,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -3600,7 +3793,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3678,7 +3870,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -3751,6 +3942,16 @@ "ieee754": "^1.1.13" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3812,7 +4013,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -3838,6 +4038,15 @@ ], "license": "CC-BY-4.0" }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chai": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", @@ -3870,6 +4079,42 @@ "node": ">=4" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -3891,7 +4136,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -3916,7 +4160,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -4059,6 +4302,10 @@ "node": ">= 10" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" "node_modules/clipboard-copy": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clipboard-copy/-/clipboard-copy-4.0.1.tgz", @@ -4153,11 +4400,19 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -4276,7 +4531,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4298,7 +4552,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -4311,14 +4564,12 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4332,6 +4583,18 @@ } } }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -4410,7 +4673,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4427,11 +4689,22 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, "license": "Apache-2.0" }, "node_modules/diff-match-patch": { @@ -4458,7 +4731,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, "license": "MIT" }, "node_modules/docs": { @@ -4499,7 +4771,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, "license": "MIT" }, "node_modules/ee-first": { @@ -4520,7 +4791,6 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, "license": "MIT" }, "node_modules/encodeurl": { @@ -4533,6 +4803,17 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -5085,7 +5366,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -5131,6 +5411,15 @@ "node": ">=4.0" } }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -5249,6 +5538,22 @@ "dev": true, "license": "MIT" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -5289,7 +5594,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5306,7 +5610,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5333,7 +5636,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -5382,7 +5684,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5497,7 +5798,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", @@ -5570,7 +5870,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -5585,7 +5884,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5668,7 +5966,6 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -5689,7 +5986,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -5702,7 +5998,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -5712,7 +6007,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -5812,6 +6106,40 @@ "dev": true, "license": "MIT" }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -5891,7 +6219,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5900,6 +6227,25 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-heading-rank": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", @@ -5918,7 +6264,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", - "dev": true, "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -5928,6 +6273,122 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", + "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-sanitize": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-5.0.1.tgz", + "integrity": "sha512-IGrgWLuip4O2nq5CugXy4GI2V8kx4sFVy5Hd4vF7AR2gxS0N9s7nEAVUyeMtZKZvzrxVsHt73XdTsno1tClIkQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.2.0", + "unist-util-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-string": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", @@ -5942,6 +6403,49 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -5964,6 +6468,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -6114,6 +6636,11 @@ "dev": true, "license": "ISC" }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==" + }, "node_modules/inquirer": { "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", @@ -6366,6 +6893,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -6387,7 +6936,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -6413,7 +6961,6 @@ "version": "2.15.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -6425,11 +6972,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6439,7 +7002,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6465,7 +7027,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -6474,6 +7035,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -6488,7 +7058,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6504,6 +7073,17 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -6560,7 +7140,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -6577,7 +7156,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -6593,7 +7171,6 @@ "version": "1.21.6", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -6717,7 +7294,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6741,7 +7317,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -6751,7 +7326,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, "license": "MIT" }, "node_modules/lint-staged": { @@ -6944,11 +7518,20 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, "license": "MIT" }, "node_modules/log-symbols": { @@ -7182,6 +7765,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -7204,6 +7796,28 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lowlight": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.1.0.tgz", + "integrity": "sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "highlight.js": "~11.9.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lowlight/node_modules/highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -7270,28 +7884,172 @@ "react": ">= 0.14.0" } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node_modules/mdast-util-from-markdown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", + "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/memoizerific": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", - "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", - "dev": true, - "license": "MIT", + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", "dependencies": { - "map-or-similar": "^1.5.0" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/merge-descriptors": { - "version": "1.0.3", + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, @@ -7311,7 +8069,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -7327,11 +8084,431 @@ "node": ">= 0.6" } }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", + "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -7438,7 +8615,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -7461,7 +8637,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mute-stream": { @@ -7475,7 +8650,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -7518,6 +8692,15 @@ "node": ">= 0.6" } }, + "node_modules/next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -7549,7 +8732,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7601,7 +8783,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -7893,7 +9074,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/package-manager-detector": { @@ -7916,6 +9096,41 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -7950,7 +9165,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7960,14 +9174,12 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -7984,7 +9196,6 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, "license": "ISC" }, "node_modules/path-to-regexp": { @@ -8031,7 +9242,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -8057,7 +9267,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8067,7 +9276,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -8181,7 +9389,6 @@ "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -8210,7 +9417,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -8228,7 +9434,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -8248,7 +9453,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -8284,7 +9488,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -8297,7 +9500,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -8323,7 +9525,6 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -8337,7 +9538,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, "license": "MIT" }, "node_modules/prelude-ls": { @@ -8430,6 +9630,15 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -8474,7 +9683,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -8666,6 +9874,31 @@ "dev": true, "license": "MIT" }, + "node_modules/react-markdown": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", + "integrity": "sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, "node_modules/react-notion-custom": { "resolved": "packages/react-notion-custom", "link": true @@ -8693,7 +9926,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -8718,7 +9950,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -8797,6 +10028,36 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-highlight/-/rehype-highlight-7.0.0.tgz", + "integrity": "sha512-QtobgRgYoQaK6p1eSr2SD1i61f7bjF2kZHAQHxeCHAuJf7ZUDMvQ7owDq9YTkmar5m5TSUol+2D3bp3KfJf/oA==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-text": "^4.0.0", + "lowlight": "^3.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-slug": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", @@ -8815,6 +10076,82 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", + "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-html": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/remark-html/-/remark-html-16.0.1.tgz", + "integrity": "sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "hast-util-sanitize": "^5.0.0", + "hast-util-to-html": "^9.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -8839,7 +10176,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", @@ -8910,7 +10246,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -8981,7 +10316,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -9048,6 +10382,18 @@ "loose-envify": "^1.1.0" } }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -9168,7 +10514,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -9181,7 +10526,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9217,7 +10561,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -9313,13 +10656,17 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "dev": true, "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -9367,6 +10714,14 @@ "url": "https://opencollective.com/storybook" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -9391,7 +10746,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -9410,7 +10764,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -9425,14 +10778,12 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9445,7 +10796,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -9457,11 +10807,23 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -9475,7 +10837,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -9494,6 +10855,14 @@ "node": ">=4" } }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -9536,11 +10905,40 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -9576,7 +10974,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9589,7 +10986,6 @@ "version": "3.4.11", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.11.tgz", "integrity": "sha512-qhEuBcLemjSJk5ajccN9xJFtM/h0AVCPaA6C92jNP+M2J8kX+eMJHI7R2HFKUvvAsMpcfLILMCFYSeDwpMmlUg==", - "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -9644,7 +11040,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -9654,7 +11049,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -9748,7 +11142,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -9773,6 +11166,24 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -9800,7 +11211,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, "license": "Apache-2.0" }, "node_modules/ts-patch": { @@ -9930,7 +11340,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true, "license": "0BSD" }, "node_modules/tsutils": { @@ -10085,11 +11494,41 @@ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "license": "MIT" }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -10099,11 +11538,34 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-visit": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -10119,7 +11581,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -10231,7 +11692,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/utils-merge": { @@ -10268,6 +11728,45 @@ "node": ">= 0.8" } }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "5.4.5", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.5.tgz", @@ -10454,6 +11953,15 @@ "defaults": "^1.0.3" } }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -10481,7 +11989,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -10544,7 +12051,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -10563,7 +12069,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -10581,7 +12086,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -10597,7 +12101,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -10610,21 +12113,18 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -10639,7 +12139,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -10652,7 +12151,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -10665,7 +12163,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -10717,7 +12214,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", - "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -10739,12 +12235,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "packages/docs": { "version": "0.1.0", "dependencies": { + "@heroicons/react": "2.1.5", + "@tailwindcss/typography": "0.5.15", + "@types/hast": "3.0.4", + "gray-matter": "4.0.3", "next": "14.2.11", + "next-themes": "0.3.0", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "react-markdown": "9.0.1", + "rehype-highlight": "7.0.0", + "rehype-raw": "7.0.0", + "remark": "15.0.1", + "remark-html": "16.0.1" }, "devDependencies": { "@types/node": "^20", @@ -10755,6 +12270,15 @@ "typescript": "^5" } }, + "packages/docs/node_modules/@swc/helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "dependencies": { + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" + } + }, "packages/docs/node_modules/next": { "version": "14.2.11", "license": "MIT", @@ -10941,6 +12465,141 @@ "typescript-eslint": "^8.0.1", "vite": "^5.4.1" } + }, + "packages/docs/node_modules/@next/swc-darwin-arm64": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.11.tgz", + "integrity": "sha512-eiY9u7wEJZWp/Pga07Qy3ZmNEfALmmSS1HtsJF3y1QEyaExu7boENz11fWqDmZ3uvcyAxCMhTrA1jfVxITQW8g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-darwin-x64": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.11.tgz", + "integrity": "sha512-lnB0zYCld4yE0IX3ANrVMmtAbziBb7MYekcmR6iE9bujmgERl6+FK+b0MBq0pl304lYe7zO4yxJus9H/Af8jbg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.11.tgz", + "integrity": "sha512-Ulo9TZVocYmUAtzvZ7FfldtwUoQY0+9z3BiXZCLSUwU2bp7GqHA7/bqrfsArDlUb2xeGwn3ZuBbKtNK8TR0A8w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.11.tgz", + "integrity": "sha512-fH377DnKGyUnkWlmUpFF1T90m0dADBfK11dF8sOQkiELF9M+YwDRCGe8ZyDzvQcUd20Rr5U7vpZRrAxKwd3Rzg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.11.tgz", + "integrity": "sha512-a0TH4ZZp4NS0LgXP/488kgvWelNpwfgGTUCDXVhPGH6pInb7yIYNgM4kmNWOxBFt+TIuOH6Pi9NnGG4XWFUyXQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.11.tgz", + "integrity": "sha512-DYYZcO4Uir2gZxA4D2JcOAKVs8ZxbOFYPpXSVIgeoQbREbeEHxysVsg3nY4FrQy51e5opxt5mOHl/LzIyZBoKA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.11.tgz", + "integrity": "sha512-PwqHeKG3/kKfPpM6of1B9UJ+Er6ySUy59PeFu0Un0LBzJTRKKAg2V6J60Yqzp99m55mLa+YTbU6xj61ImTv9mg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.11.tgz", + "integrity": "sha512-0U7PWMnOYIvM74GY6rbH6w7v+vNPDVH1gUhlwHpfInJnNe5LkmUZqhp7FNWeNa5wbVgRcRi1F1cyxp4dmeLLvA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "packages/docs/node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.11.tgz", + "integrity": "sha512-gQpS7mcgovWoaTG1FbS5/ojF7CGfql1Q0ZLsMrhcsi2Sr9HEqsUZ70MPJyaYBXbk6iEAP7UXMD9HC8KY1qNwvA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } diff --git a/packages/docs/app/[lang]/guide/[group]/[slug]/guide-page.tsx b/packages/docs/app/[lang]/guide/[group]/[slug]/guide-page.tsx new file mode 100644 index 0000000..c5e2407 --- /dev/null +++ b/packages/docs/app/[lang]/guide/[group]/[slug]/guide-page.tsx @@ -0,0 +1,101 @@ +"use client"; + +import React, { useEffect } from "react"; +import ReactMarkdown from "react-markdown"; +import rehypeRaw from "rehype-raw"; +import rehypeHighlight from "rehype-highlight"; +import { + DynamicLayout, + MobileSidebar, + NavigationButton, + Sidebar, + TOC, +} from "@/components"; +import { generateTOC } from "@/lib/generateTOC"; + +interface GuidePageProps { + params: { + lang: string; + group: string; + slug: string; + }; + content: string; + title: string; + prevDocument: any; + nextDocument: any; + allDocuments: any[]; +} + +export default function GuidePage({ + params, + content, + title, + prevDocument, + nextDocument, + allDocuments, +}: GuidePageProps) { + const { lang, group, slug } = params; + const tocItems = generateTOC(content); + + useEffect(() => { + const headings = document.querySelectorAll("h1, h2, h3, h4, h5, h6"); + headings.forEach((heading) => { + heading.id = + heading.textContent?.toLowerCase().replace(/\s+/g, "-") ?? ""; + }); + }, [content]); + + return ( + + } + mobileSidebar={ + + } + toc={} + > +
+

+ {group} > {title} +

+ + {content} + +
+
+
+ {prevDocument && ( + + )} +
+
+ {nextDocument && ( + + )} +
+
+
+ ); +} diff --git a/packages/docs/app/[lang]/guide/[group]/[slug]/page.tsx b/packages/docs/app/[lang]/guide/[group]/[slug]/page.tsx new file mode 100644 index 0000000..74f647b --- /dev/null +++ b/packages/docs/app/[lang]/guide/[group]/[slug]/page.tsx @@ -0,0 +1,51 @@ +import { getAllDocuments, getDocumentBySlug } from "@/lib/mdx"; +import { Metadata } from "next"; +import GuidePage from "./guide-page"; + +interface GuidePageProps { + params: { + lang: string; + group: string; + slug: string; + }; +} + +// TODO: Add URL and image +export async function generateMetadata({ + params, +}: GuidePageProps): Promise { + const { lang, group, slug } = params; + const { title, content } = await getDocumentBySlug(lang, group, slug); + + return { + title: `${title} | react-notion-custom Docs`, + description: content.slice(0, 160), + openGraph: { + title: `${title} | react-notion-custom Docs`, + description: content.slice(0, 160), + // url: "", + }, + alternates: { + // canonical: "", + }, + }; +} + +export default async function Page({ params }: GuidePageProps) { + const { lang, group, slug } = params; + + const { content, title, prevDocument, nextDocument } = + await getDocumentBySlug(lang, group, slug); + const allDocuments = getAllDocuments(lang); + + return ( + + ); +} diff --git a/packages/docs/app/[lang]/page.tsx b/packages/docs/app/[lang]/page.tsx new file mode 100644 index 0000000..50596d8 --- /dev/null +++ b/packages/docs/app/[lang]/page.tsx @@ -0,0 +1,9 @@ +import MouseImageEffect from "@/components/effects/mouse-image-effect"; + +export default function Home({ + params: { lang }, +}: { + params: { lang: string }; +}) { + return ; +} diff --git a/packages/docs/app/favicon.ico b/packages/docs/app/favicon.ico index 718d6fe..71ca2b0 100644 Binary files a/packages/docs/app/favicon.ico and b/packages/docs/app/favicon.ico differ diff --git a/packages/docs/app/fonts/GeistMonoVF.woff b/packages/docs/app/fonts/GeistMonoVF.woff deleted file mode 100644 index f2ae185..0000000 Binary files a/packages/docs/app/fonts/GeistMonoVF.woff and /dev/null differ diff --git a/packages/docs/app/fonts/GeistVF.woff b/packages/docs/app/fonts/GeistVF.woff deleted file mode 100644 index 1b62daa..0000000 Binary files a/packages/docs/app/fonts/GeistVF.woff and /dev/null differ diff --git a/packages/docs/app/fonts/Pretendard-Bold.woff b/packages/docs/app/fonts/Pretendard-Bold.woff new file mode 100644 index 0000000..7837ae5 Binary files /dev/null and b/packages/docs/app/fonts/Pretendard-Bold.woff differ diff --git a/packages/docs/app/fonts/Pretendard-Regular.woff b/packages/docs/app/fonts/Pretendard-Regular.woff new file mode 100644 index 0000000..e3b3a35 Binary files /dev/null and b/packages/docs/app/fonts/Pretendard-Regular.woff differ diff --git a/packages/docs/app/fonts/Pretendard-SemiBold.woff b/packages/docs/app/fonts/Pretendard-SemiBold.woff new file mode 100644 index 0000000..682e7a4 Binary files /dev/null and b/packages/docs/app/fonts/Pretendard-SemiBold.woff differ diff --git a/packages/docs/app/fonts/Pretendard-Thin.woff b/packages/docs/app/fonts/Pretendard-Thin.woff new file mode 100644 index 0000000..d28e448 Binary files /dev/null and b/packages/docs/app/fonts/Pretendard-Thin.woff differ diff --git a/packages/docs/app/globals.css b/packages/docs/app/globals.css index 13d40b8..caacb7c 100644 --- a/packages/docs/app/globals.css +++ b/packages/docs/app/globals.css @@ -2,26 +2,85 @@ @tailwind components; @tailwind utilities; -:root { - --background: #ffffff; - --foreground: #171717; +/* CSS Reset */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } +html, +body { + height: 100%; +} + +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} + +input, +button, +textarea, +select { + font: inherit; +} + +button { + cursor: pointer; +} + +a { + text-decoration: none; + color: inherit; } +ul, +ol { + list-style: none; +} + +/* Global Styles */ body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; + line-height: 1.6; + background-color: #f8f9fa; + color: #343a40; } -@layer utilities { - .text-balance { - text-wrap: balance; +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: bold; + line-height: 1.2; +} + +@keyframes shake { + 0% { + transform: rotate(0deg); + } + 25% { + transform: rotate(5deg); } + 50% { + transform: rotate(0eg); + } + 75% { + transform: rotate(-5deg); + } + 100% { + transform: rotate(0deg); + } +} +.logo-image { + transition: transform 0.1s ease-in-out; +} +.logo-image:hover { + animation: shake 0.5s ease-in-out; } diff --git a/packages/docs/app/layout.tsx b/packages/docs/app/layout.tsx index a36cde0..0724422 100644 --- a/packages/docs/app/layout.tsx +++ b/packages/docs/app/layout.tsx @@ -1,21 +1,28 @@ import type { Metadata } from "next"; import localFont from "next/font/local"; import "./globals.css"; +import { Navigation, ThemeProvider } from "@/components"; -const geistSans = localFont({ - src: "./fonts/GeistVF.woff", - variable: "--font-geist-sans", - weight: "100 900", -}); -const geistMono = localFont({ - src: "./fonts/GeistMonoVF.woff", - variable: "--font-geist-mono", +const pretendard = localFont({ + src: "./fonts/Pretendard-Regular.woff", + variable: "--font-pretendard", weight: "100 900", }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "react-notion-custom Docs", + description: + "Comprehensive documentation for react-notion-custom library, a powerful tool for rendering Notion pages in React applications.", + keywords: "react, notion, custom, documentation, library, rendering", + openGraph: { + title: "react-notion-custom Documentation", + description: + "Learn how to use react-notion-custom to render Notion pages in your React apps.", + type: "website", + // TODO: Add URL and image + // url: "", + // image: "", + }, }; export default function RootLayout({ @@ -24,11 +31,12 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - - {children} + + + + +
{children}
+
); diff --git a/packages/docs/app/page.tsx b/packages/docs/app/page.tsx deleted file mode 100644 index 433c8aa..0000000 --- a/packages/docs/app/page.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import Image from "next/image"; - -export default function Home() { - return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - app/page.tsx - - . -
  2. -
  3. Save and see your changes instantly.
  4. -
- - -
- -
- ); -} diff --git a/packages/docs/components/dynamic-layout.tsx b/packages/docs/components/dynamic-layout.tsx new file mode 100644 index 0000000..d8b8e71 --- /dev/null +++ b/packages/docs/components/dynamic-layout.tsx @@ -0,0 +1,30 @@ +"use client"; + +import useIsMobile from "../hooks/useIsMobile"; + +interface DynamicLayoutProps { + sidebar: React.ReactNode; + toc: React.ReactNode; + mobileSidebar: React.ReactNode; + children: React.ReactNode; +} + +export default function DynamicLayout({ + sidebar, + toc, + mobileSidebar, + children, +}: DynamicLayoutProps) { + const isMobile = useIsMobile(); + + return ( +
+ {!isMobile &&
{sidebar}
} + {isMobile &&
{mobileSidebar}
} +
{children}
+ {!isMobile &&
{toc}
} +
+ ); +} diff --git a/packages/docs/components/effects/mouse-image-effect.tsx b/packages/docs/components/effects/mouse-image-effect.tsx new file mode 100644 index 0000000..2d1e9f9 --- /dev/null +++ b/packages/docs/components/effects/mouse-image-effect.tsx @@ -0,0 +1,71 @@ +"use client"; +import React, { MouseEvent, useEffect, useRef, useState } from "react"; + +const images = Array(16).fill("/logo.svg"); + +export default function MouseImageEffect() { + const [imagePositions, setImagePositions] = useState< + { src: string; x: number; y: number }[] + >([]); + const containerRef = useRef(null); + + useEffect(() => { + images.forEach((src) => { + const img = new Image(); + img.src = src; + }); + }, []); + + const handleMouseMove = (e: MouseEvent) => { + if (!containerRef.current) return; + + const { clientX, clientY } = e; + const { left, top } = containerRef.current.getBoundingClientRect(); + + const x = clientX - left; + const y = clientY - top; + + if (imagePositions.length < images.length) { + setImagePositions((prev) => [ + ...prev, + { src: images[prev.length], x, y }, + ]); + } else { + setImagePositions((prev) => [ + ...prev.slice(1), + { src: images[prev.length % images.length], x, y }, + ]); + } + }; + + return ( +
+
+

+ react-notion-custom +

+

+ Create Your Custom Blog with Notion +

+
+ + {imagePositions.map((image, index) => ( + {`Image + ))} +
+ ); +} diff --git a/packages/docs/components/index.ts b/packages/docs/components/index.ts new file mode 100644 index 0000000..32b6e73 --- /dev/null +++ b/packages/docs/components/index.ts @@ -0,0 +1,9 @@ +export { default as Navigation } from "./navigation"; +export { default as LanguageSelector } from "./language-selector"; +export { default as Sidebar } from "./sidebar"; +export { ThemeProvider } from "./theme-provider"; +export { default as ThemeToggle } from "./theme-toggle"; +export { default as TOC } from "./toc"; +export { default as DynamicLayout } from "./dynamic-layout"; +export { default as NavigationButton } from "./navigation-button"; +export { default as MobileSidebar } from "./mobile-sidebar"; diff --git a/packages/docs/components/language-selector.tsx b/packages/docs/components/language-selector.tsx new file mode 100644 index 0000000..5345b2b --- /dev/null +++ b/packages/docs/components/language-selector.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { useState, useEffect, useRef } from "react"; +import { useRouter, usePathname } from "next/navigation"; +import { GlobeAltIcon } from "@heroicons/react/24/solid"; + +const languages = [ + { code: "en", name: "English" }, + { code: "kr", name: "한국어" }, +]; + +export default function LanguageSelector() { + const router = useRouter(); + const pathname = usePathname(); + const [currentLang, setCurrentLang] = useState("en"); + const [isMenuOpen, setIsMenuOpen] = useState(false); + const menuRef = useRef(null); + + useEffect(() => { + const lang = pathname.split("/")[1]; + if (languages.some((l) => l.code === lang)) { + setCurrentLang(lang); + } + }, [pathname]); + + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if (menuRef.current && !menuRef.current.contains(event.target as Node)) { + setIsMenuOpen(false); + } + } + + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); + + const changeLang = (newLang: string) => { + const newPathname = pathname.replace(`/${currentLang}`, `/${newLang}`); + router.push(newPathname); + }; + + return ( +
+ + {isMenuOpen && ( +
+
+ {languages.map((lang) => ( + + ))} +
+
+ )} +
+ ); +} diff --git a/packages/docs/components/mobile-sidebar.tsx b/packages/docs/components/mobile-sidebar.tsx new file mode 100644 index 0000000..e009e05 --- /dev/null +++ b/packages/docs/components/mobile-sidebar.tsx @@ -0,0 +1,103 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; +import { ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/24/solid"; +import ThemeToggle from "./theme-toggle"; + +type Document = { + title: string; + slug: string; + group: string; + order: number; +}; + +type MobileSidebarProps = { + documents: Document[]; + currentSlug: string; + currentGroup: string; + lang: string; +}; + +export default function MobileSidebar({ + documents, + currentSlug, + currentGroup, + lang, +}: MobileSidebarProps) { + const [isOpen, setIsOpen] = useState(false); + const [openGroup, setOpenGroup] = useState(null); + + const groupedDocuments = documents.reduce( + (acc, doc) => { + if (!acc[doc.group]) { + acc[doc.group] = []; + } + acc[doc.group].push(doc); + return acc; + }, + {} as Record, + ); + + const toggleDropdown = () => setIsOpen(!isOpen); + const toggleGroup = (group: string) => { + setOpenGroup(openGroup === group ? null : group); + }; + + return ( +
+ + {isOpen && ( +
+ {Object.entries(groupedDocuments).map(([group, docs]) => ( +
+ + {openGroup === group && ( +
    + {docs.map((doc) => ( +
  • + + {doc.title} + + +
  • + ))} +
+ )} +
+ ))} +
+ +
+
+ )} +
+ ); +} diff --git a/packages/docs/components/navigation-button.tsx b/packages/docs/components/navigation-button.tsx new file mode 100644 index 0000000..c8b5419 --- /dev/null +++ b/packages/docs/components/navigation-button.tsx @@ -0,0 +1,37 @@ +import Link from "next/link"; +import { ChevronRightIcon, ChevronLeftIcon } from "@heroicons/react/24/solid"; + +interface NavigationButtonProps { + document: { + group: string; + slug: string; + title: string; + }; + lang: string; + direction: "prev" | "next"; +} + +export default function NavigationButton({ + document, + lang, + direction, +}: NavigationButtonProps) { + return ( + + {direction === "prev" ? ( +
+ +

{document.title}

+
+ ) : ( +
+

{document.title}

+ +
+ )} + + ); +} diff --git a/packages/docs/components/navigation.tsx b/packages/docs/components/navigation.tsx new file mode 100644 index 0000000..a5c5d31 --- /dev/null +++ b/packages/docs/components/navigation.tsx @@ -0,0 +1,48 @@ +"use client"; + +import Link from "next/link"; +import { useParams } from "next/navigation"; +import Image from "next/image"; +import LanguageSelector from "./language-selector"; + +export default function Navigation() { + const params = useParams(); + const lang = (params.lang as string) || "en"; + + return ( + + ); +} diff --git a/packages/docs/components/sidebar.tsx b/packages/docs/components/sidebar.tsx new file mode 100644 index 0000000..72e7885 --- /dev/null +++ b/packages/docs/components/sidebar.tsx @@ -0,0 +1,68 @@ +import Link from "next/link"; +import ThemeToggle from "./theme-toggle"; +import { ChevronRightIcon } from "@heroicons/react/24/solid"; + +type Document = { + title: string; + slug: string; + group: string; + order: number; +}; + +type SidebarProps = { + documents: Document[]; + currentSlug: string; + currentGroup: string; + lang: string; +}; + +export default function Sidebar({ + documents, + currentSlug, + currentGroup, + lang, +}: SidebarProps) { + const groupedDocuments = documents.reduce( + (acc, doc) => { + if (!acc[doc.group]) { + acc[doc.group] = []; + } + acc[doc.group].push(doc); + return acc; + }, + {} as Record, + ); + + return ( + + ); +} diff --git a/packages/docs/components/theme-provider.tsx b/packages/docs/components/theme-provider.tsx new file mode 100644 index 0000000..a11e499 --- /dev/null +++ b/packages/docs/components/theme-provider.tsx @@ -0,0 +1,8 @@ +"use client"; + +import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { type ThemeProviderProps } from "next-themes/dist/types"; + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return {children}; +} diff --git a/packages/docs/components/theme-toggle.tsx b/packages/docs/components/theme-toggle.tsx new file mode 100644 index 0000000..1cd899e --- /dev/null +++ b/packages/docs/components/theme-toggle.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { useTheme } from "next-themes"; +import { useEffect, useState } from "react"; +import { SunIcon, MoonIcon } from "@heroicons/react/24/solid"; + +export default function ThemeToggle() { + const [mounted, setMounted] = useState(false); + const { theme, setTheme } = useTheme(); + + useEffect(() => setMounted(true), []); + + if (!mounted) return null; + + return ( + + ); +} diff --git a/packages/docs/components/toc.tsx b/packages/docs/components/toc.tsx new file mode 100644 index 0000000..9eeb24a --- /dev/null +++ b/packages/docs/components/toc.tsx @@ -0,0 +1,27 @@ +interface TOCItem { + id: string; + title: string; +} + +interface TOCProps { + items: TOCItem[]; +} + +export default function TOC({ items }: TOCProps) { + return ( + + ); +} diff --git a/packages/docs/constants/group.ts b/packages/docs/constants/group.ts new file mode 100644 index 0000000..fcb1bc1 --- /dev/null +++ b/packages/docs/constants/group.ts @@ -0,0 +1,12 @@ +export const GROUPS = [ + { id: "getting-started", name: "Getting Started", order: "01" }, + { id: "customization-guide", name: "Customization Guide", order: "02" }, + { id: "block-types", name: "Block Types", order: "03" }, +] as const; + +export type GroupId = (typeof GROUPS)[number]["id"]; + +export function getGroupOrder(groupId: GroupId): string { + const group = GROUPS.find((g) => g.id === groupId); + return group ? group.order : "00"; +} diff --git a/packages/docs/content/guide/en/01. getting-started/01. introduction.md b/packages/docs/content/guide/en/01. getting-started/01. introduction.md new file mode 100644 index 0000000..f3d3fdf --- /dev/null +++ b/packages/docs/content/guide/en/01. getting-started/01. introduction.md @@ -0,0 +1,102 @@ +--- +group: "getting-started" +order: 1 +title: "Project Introduction" +slug: "introduction" +description: "An overview of the React-Notion-Custom project, its key features, and potential applications." +--- + +# Introduction to React-Notion-Custom Project + +## What is React-Notion-Custom? + +React-Notion-Custom is a tool that allows you to easily bring Notion's powerful content creation capabilities to your website. This library enables you to render content created in Notion directly on your React-based website. It's a "magic potion" for both developers and content creators - allowing developers to quickly produce results and providing content creators with a convenient management tool. ✨ + +## Key Features and Provided Value + +### 🛠️ React Rendering of Notion Data + +You can easily convert various content from Notion such as text, images, lists, code blocks, etc., into React components. Notion pages are reborn on the web with the following structure: + +```jsx +import { Notion, type NotionPageData } from 'react-notion-custom'; + +interface NotionPageProps { + pageData: NotionPageData; +} + +function NotionPage({ pageData }: NotionPageProps) { + return ( + + + + + + + + ); +} +``` + +In this example, the `NotionPageData` type defines the data structure of a Notion page. This allows you to use TypeScript's type checking feature to write more stable code. + +### 🎨 Freedom of Customization + +You can easily change themes by just tweaking CSS, or partially modify the provided components to customize only the parts you need. You can even create completely new components and combine them with React-Notion-Custom. It offers unlimited possibilities for developers who handle code. + +### 🚀 Rapid Site Construction + +You can easily extract Notion data using the Notion-dump CLI and quickly build static sites through frameworks like Next.js. The process of building a site with just a few commands feels like a website is completed right from the text. + +```bash +npx notion-dump --page YOUR_PAGE_URL --auth YOUR_API_KEY +``` + +When you run notion-dump, Notion data is extracted into the following folder structure: + +``` +my-notion-project/ +├── notion-data/ +│ ├── page-slug-1.json +│ ├── page-slug-2.json +│ └── ... +└── public/ + └── images/ + ├── page-slug-1/ + │ ├── image1.png + │ └── image2.jpg + ├── page-slug-2/ + │ └── image1.png + └── ... +``` + +- `notion-data/`: The content of each Notion page is stored in JSON format. The file name is generated based on the page's slug. +- `public/images/`: Images used in Notion pages are stored and categorized by each page. + +The extracted data can be easily integrated with React-Notion-Custom components, allowing you to quickly convert Notion content into a website. By simply passing the content of the JSON file to React components, the structure and style of the Notion page are reflected directly on the website. + +## Target Users and Their Potential Applications + +### Developers + +Developers are given the freedom to easily render and customize content created in Notion on websites. If you want to build a website quickly or style it as you want beyond the limitations of commercial services, React-Notion-Custom is the answer. + +### Designers and Creators + +You can directly reflect content written in Notion on the web, allowing you to quickly update content while maintaining design consistency. + +### Potential Use Cases + +- **Personal Blog**: Easily write posts in Notion and automatically reflect them on your website. +- **Company Introduction and Recruitment Pages**: Quickly update company profiles or recruitment information using Notion. +- **Portfolio Sites**: Easily update projects and works, making portfolio management much easier. + +## Why Choose React-Notion-Custom + +1. **Developer-Centric Customization**: You can modify even the finest details that can't be touched in other commercial services. The infinite possibilities through code - this is the charm of React-Notion-Custom. + +2. **Freedom of Open Source**: Everything is transparent and can be handled directly by you. If needed, you can modify the code and self-host the project on your own server, eliminating cost burdens. + +3. **Quick Results and High Efficiency**: You can write content in Notion and use it directly on your website with simple settings. The process of content creation and deployment is further simplified. + +React-Notion-Custom is the bridge that turns your Notion pages into amazing websites. No more complicated setups, start right from Notion now! diff --git a/packages/docs/content/guide/en/01. getting-started/02. quick-start.md b/packages/docs/content/guide/en/01. getting-started/02. quick-start.md new file mode 100644 index 0000000..0754f68 --- /dev/null +++ b/packages/docs/content/guide/en/01. getting-started/02. quick-start.md @@ -0,0 +1,216 @@ +--- +group: "getting-started" +order: 2 +title: "Quick Start Guide" +slug: "quick-start" +description: "A step-by-step guide on building a website with Notion content using React-Notion-Custom." +--- + +# React-Notion-Custom Quick Start Guide + +## 2.1. Installation and Setup + +### Installing React-Notion-Custom + +Install React-Notion-Custom and Notion-dump, a CLI tool for extracting Notion data. + +```bash +npm install react-notion-custom notion-dump +``` + +### Setting up a Next.js Project + +If you don't have a Next.js project, create a new one. Next.js provides optimal performance with static site generation and server-side rendering support. + +```bash +npx create-next-app my-notion-blog +cd my-notion-blog +``` + +### Generating a Notion API Key + +1. Go to the Notion developer portal (https://developers.notion.com/). +2. Create a new integration. +3. Securely store the generated API key. + +## 2.2. Extracting Notion Data (notion-dump) + +Use the Notion-dump CLI to extract Notion data in JSON format and prepare it for use on your website. + +### Using the Data Extraction Command + +Extract data using the Notion page URL and API key. + +```bash +npx notion-dump --page YOUR_PAGE_URL --auth YOUR_API_KEY +``` + +### notion-dump Folder Structure and Options + +notion-dump is tailored to the Next.js project structure by default. The extracted data is stored in the following structure: + +``` +my-notion-blog/ +├── notion-data/ +│ ├── page-id-1.json +│ ├── page-id-2.json +│ └── ... +└── public/ + └── images/ + ├── page-id-1/ + │ ├── image1.png + │ └── image2.jpg + ├── page-id-2/ + │ └── image1.png + └── ... +``` + +Main options for notion-dump: + +- `--dir`: Specifies the directory where JSON files will be stored. Default is `./notion-data`. +- `--image-dir`: Specifies the directory where image files will be stored. Default is `./public/images`. + +For example, if you want to change the storage location: + +```bash +npx notion-dump --page YOUR_PAGE_URL --auth YOUR_API_KEY --dir ./data --image-dir ./public/assets/images +``` + +If options are not specified, default values are used, which are optimized for the Next.js project structure. + +## 2.3. Rendering Notion Data in React + +Render the extracted Notion data using React components. This section covers basic page structure and component usage. + +### Basic Rendering Example Code + +A simple example of rendering Notion data as React components. + +```jsx +import { Notion } from "react-notion-custom"; +import pageData from "./notion-data/your-page-id.json"; + +function NotionPage() { + return ( + + + + + + + + ); +} + +export default NotionPage; +``` + +### Explanation + +- The `` component takes Notion data and constructs the page. +- Basic Notion elements like ``, ``, `<Blocks>` can be expressed on the web as they are. + +## 2.4. Creating the First Page with Next.js Integration + +Generate dynamic web pages using Next.js and optimize performance using Static Site Generation (SSG). + +### Creating Next.js Pages and Setting Up Dynamic Routing + +Generate each post page with dynamic routing and use `getStaticPaths` and `getStaticProps` for static site generation. + +```jsx +// pages/[slug].js +import { Notion } from "react-notion-custom"; +import posts from "../posts"; + +export async function getStaticPaths() { + const paths = posts.map((post) => ({ + params: { slug: post.slug }, + })); + return { paths, fallback: false }; +} + +export async function getStaticProps({ params }) { + const post = posts.find((p) => p.slug === params.slug); + return { props: { post } }; +} + +export default function PostPage({ post }) { + return ( + <Notion> + <Notion.Blocks blocks={post.content.blocks} /> + </Notion> + ); +} +``` + +### Explanation + +- `getStaticPaths` pre-generates the paths for the posts. +- `getStaticProps` fetches data for each post and renders it. + +## 2.5. Creating a Blog + +This section explains how to set up the overall structure of the blog and how to manage and display each post. + +### Setting up posts/index.js + +Centrally manage blog post data. Organize the metadata and content of each post into an array for use. + +```javascript +// posts/index.js +import post1Content from "../notion-data/post1.json"; +import post2Content from "../notion-data/post2.json"; + +const posts = [ + { + slug: "post1", + title: "First Blog Post", + date: "2023-10-01", + description: "Description of the first blog post.", + content: post1Content, + }, + { + slug: "post2", + title: "Second Blog Post", + date: "2023-10-05", + description: "Description of the second blog post.", + content: post2Content, + }, +]; + +export default posts; +``` + +### Using the Data: Blog Main Page + +Use the `posts` array to render a list of posts on the main page. + +```jsx +// pages/index.js +import Link from "next/link"; +import posts from "../posts"; + +export default function Home() { + return ( + <div> + <h1>Blog Post List</h1> + <ul> + {posts.map((post) => ( + <li key={post.slug}> + <Link href={`/${post.slug}`}> + <a>{post.title}</a> + </Link> + <p>{post.description}</p> + <small>{post.date}</small> + </li> + ))} + </ul> + </div> + ); +} +``` + +### Creating Individual Post Pages + +Each post page is automatically generated through dynamic routing. Posts written in Notion are directly reflected on the website, allowing for easy blog updates. diff --git a/packages/docs/content/guide/en/02. customization-guide/01. structure-and-customization.md b/packages/docs/content/guide/en/02. customization-guide/01. structure-and-customization.md new file mode 100644 index 0000000..268206b --- /dev/null +++ b/packages/docs/content/guide/en/02. customization-guide/01. structure-and-customization.md @@ -0,0 +1,175 @@ +--- +group: "customization-guide" +order: 1 +title: "Understanding React-Notion-Custom Structure and Customization" +slug: "structure-and-customization" +description: "Learn about the data structure of React-Notion-Custom and effective customization methods based on this understanding." +--- + +# Understanding React-Notion-Custom Structure and Customization + +To effectively customize React-Notion-Custom, it's essential to first understand its basic structure and data flow. This section examines the structure of Notion data and explains how to create custom components based on this understanding. + +## Understanding the Data Structure + +The Notion data used by React-Notion-Custom is structured in JSON format and includes page information and detailed content for each block. Understanding this structure is the first step towards effective customization. + +### Basic Data Structure + +```json +{ + "object": "page", + "id": "page-id", + "created_time": "2024-09-20T13:54:00.000Z", + "last_edited_time": "2024-09-21T04:28:00.000Z", + "cover": null, + "icon": null, + "parent": { + "type": "page_id", + "page_id": "parent-page-id" + }, + "properties": { + "title": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Page Title", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "color": "default" + }, + "plain_text": "Page Title" + } + ] + } + }, + "blocks": [ + { + "object": "block", + "id": "block-id-1", + "type": "toggle", + "toggle": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "Toggle content", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "color": "default" + }, + "plain_text": "Toggle content" + } + ], + "color": "default" + }, + "blocks": [ + { + "object": "block", + "id": "block-id-2", + "type": "paragraph", + "paragraph": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "Paragraph inside toggle", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "color": "default" + }, + "plain_text": "Paragraph inside toggle" + } + ], + "color": "default" + } + } + ] + } + ] +} +``` + +### Key Structural Elements + +1. **Page Metadata**: Includes basic page information such as `id`, `created_time`, `last_edited_time`, `parent`, etc. + +2. **Cover and Icon**: Information about the page's cover image and icon. This can be used when applying custom designs. + +3. **Properties**: Page property information, mainly including the page title (`title`). This information can be used when creating custom headers. + +4. **Blocks**: An array of blocks that make up the page content. Each block has the following structure: + + - `object`: Always "block" + - `id`: Unique identifier for the block + - `type`: Block type (e.g., "toggle", "paragraph", "heading_1", etc.) + - `[type]`: A key corresponding to the block type, containing specific content for that block. + - `blocks`: An array of child blocks. This forms a recursive structure. + +5. **Recursive Structure**: Each block within the `blocks` array can have its own `blocks` array, allowing for nested structures. This is important when customizing nested content such as toggles and lists. + +6. **rich_text**: Most text content is represented as a `rich_text` array, including text style information (`annotations`). This allows for fine-grained customization of text styles. + +## Component Structure for Customization + +The basic component structure of React-Notion-Custom is as follows: + +<pre style="font-family: monospace; line-height: 1.2; white-space: pre;"> +┌────────────────────────────────────────────────────────────────┐ +│ <Notion> │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ <Cover /> │ │ +│ │ // Page cover image │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────┐ │ +│ │ <Body> │ │ +│ │ ┌──────────────────────┐ │ │ +│ │ │ <Title /> │ │ │ +│ │ │ // Page title │ │ │ +│ │ └──────────────────────┘ │ │ +│ │ ┌──────────────────────┐ │ │ +│ │ │ <Blocks> │ │ │ +│ │ │ ┌──────────────────┐ │ │ │ +│ │ │ │<Block type="...">│ │ │ │ +│ │ │ │ // e.g. Heading │ │ │ │ +│ │ │ └──────────────────┘ │ │ │ +│ │ │ ┌──────────────────┐ │ │ │ +│ │ │ │<Block type="...">│ │ │ │ +│ │ │ │ // e.g. Para │ │ │ │ +│ │ │ └──────────────────┘ │ │ │ +│ │ │ ... │ │ │ +│ │ │ // More blocks │ │ │ +│ │ └──────────────────────┘ │ │ +│ └────────────────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────┘ +</pre> + +In this structure, the `<Body>` component occupies about 60% of the total width and is centered. You can customize each component based on this layout. + +## Customization Strategies + +1. **Custom Components for Each Block**: Create custom components for each block type (`paragraph`, `heading_1`, `toggle`, etc.) to override default styles and behaviors. + +2. **Style Customization**: Use CSS variables and classes to adjust the overall design. + +3. **Layout Modification**: Adjust the width or alignment of the `<Body>` component to change the overall layout. + +4. **Utilize Recursive Rendering**: Implement complex layouts or interactions using the nested block structure. + +5. **Leverage Metadata**: Use page metadata, cover images, icons, etc. to create rich UIs. + +Understanding these structures and strategies allows you to create highly customized Notion-based websites using React-Notion-Custom. The next section will explore specific customization methods for each element. diff --git a/packages/docs/content/guide/en/02. customization-guide/02. custom-component.md b/packages/docs/content/guide/en/02. customization-guide/02. custom-component.md new file mode 100644 index 0000000..998072e --- /dev/null +++ b/packages/docs/content/guide/en/02. customization-guide/02. custom-component.md @@ -0,0 +1,215 @@ +--- +group: "customization-guide" +order: 2 +title: "Custom Component Usage" +slug: "custom-component-usage" +description: "Learn how to customize and effectively use components in React-Notion-Custom." +--- + +# Custom Component Usage + +React-Notion-Custom provides default components for various Notion block types. This section explains how to use and customize these default components, as well as how to create new custom components. + +## Examples of Using Basic Components + +### Heading Component + +The Heading component renders Notion's title block. Here's an example of customizing the Heading component: + +```tsx +import React from "react"; +import { Heading, type HeadingArgs } from "react-notion-custom"; + +const CustomHeading: React.FC<HeadingArgs> = (props) => { + // Add underline to level 3 headings + if (props.type === "heading_3") { + return <Heading {...props} style={{ textDecoration: "underline" }} />; + } + return <Heading {...props} />; +}; + +export default CustomHeading; +``` + +In this example, we check the `level` property to change the style for a specific heading level. + +### Paragraph Component + +The Paragraph component renders regular text blocks. Here's an example of customizing the Paragraph component: + +```tsx +import React from "react"; +import { Paragraph, type ParagraphArgs } from "react-notion-custom"; + +const CustomParagraph: React.FC<ParagraphArgs> = (props) => { + return ( + <Paragraph + {...props} + className="custom-paragraph" + style={{ lineHeight: "1.8", marginBottom: "1em" }} + /> + ); +}; + +export default CustomParagraph; +``` + +In this example, we adjust the line spacing and bottom margin for all paragraphs and add a custom class. + +## Example of Customizing the Toggle Component + +The Toggle component implements Notion's toggle block. Here's an advanced example of customizing the Toggle component: + +```tsx +import React, { useState } from "react"; +import { Toggle, type ToggleArgs } from "react-notion-custom"; +import { ChevronDown, ChevronRight } from "your-icon-library"; + +const CustomToggle: React.FC<ToggleArgs> = (props) => { + const [isOpen, setIsOpen] = useState(false); + + const handleChangeOpen = (open: boolean) => { + setIsOpen(open); + // You can add additional logic here + console.log(`Toggle state changed to: ${open}`); + }; + + return ( + <Toggle {...props} isOpen={isOpen} onChangeOpen={handleChangeOpen}> + <Toggle.Icon> + {isOpen ? <ChevronDown size={20} /> : <ChevronRight size={20} />} + </Toggle.Icon> + <Toggle.Content>{props.children}</Toggle.Content> + </Toggle> + ); +}; + +export default CustomToggle; +``` + +In this example: + +1. We use `useState` to manage the open/closed state of the toggle. +2. The `handleChangeOpen` function handles state changes and can implement additional logic as needed. +3. We pass `isOpen` and `onChangeOpen` props to the `Toggle` component to directly control its state. +4. We display different icons based on the `isOpen` state. + +If no content is provided to `<Toggle.Icon>`, the default icon will be used. + +## Applying Custom Components + +Here's how to use custom components in React-Notion-Custom: + +```jsx +import { Notion } from "react-notion-custom"; +import CustomHeading from "./CustomHeading"; +import CustomParagraph from "./CustomParagraph"; +import CustomToggle from "./CustomToggle"; + +const MyNotionPage = ({ pageData }) => { + const customComponents = { + heading_1: CustomHeading, + heading_2: CustomHeading, + heading_3: CustomHeading, + paragraph: CustomParagraph, + toggle: CustomToggle, + }; + + return ( + <Notion custom={customComponents}> + <Notion.Body> + <Notion.Blocks blocks={pageData.blocks} /> + </Notion.Body> + </Notion> + ); +}; +``` + +In this example, we pass custom components to the Notion component through the `custom` prop. You can specify a custom component for each block type. + +## Creating a Completely Custom Component + +You can also create entirely new components without using React-Notion-Custom's basic components. Here's an example of creating a Todo component from scratch: + +```tsx +import React from "react"; +import { RichText, type TodoProps } from "react-notion-custom"; + +const Todo: React.FC<TodoProps> = ({ children, ...props }) => { + const { + to_do: { color, rich_text: texts, checked }, + } = props; + + const colorClass = color !== "default" ? `notion-${color}` : ""; + + return ( + <div className={`notion-block notion-to-do ${colorClass}`}> + <div className="notion-to-do-item"> + <div className="notion-to-do-item-content"> + <input + type="checkbox" + checked={checked} + readOnly + className="notion-to-do-checkbox" + /> + <div + className={`notion-to-do-text ${checked ? "notion-to-do-checked" : ""}`} + > + <RichText props={texts} /> + </div> + </div> + {children} + </div> + </div> + ); +}; + +export default Todo; +``` + +Points to note in this example: + +- We only import the RichText component from react-notion-custom. This is to handle complex text rendering. +- All CSS class names start with notion-. This follows React-Notion-Custom's styling rules. +- We add a class in the format `notion-${color}`. For the default color ("default"), we don't apply an additional class. +- The component accepts a children prop to render nested content. This is to support nested structures. + +## Precautions When Creating Components + +1. **Type Safety**: Use TypeScript to clearly define prop types. Utilize the types provided by React-Notion-Custom (e.g., `HeadingArgs`, `ParagraphArgs`). +2. **Prop Passing**: Use `{...props}` to pass all props from custom components to basic components. This maintains type safety while preventing unnecessary prop listing. +3. **Style Overriding**: Be careful not to completely replace existing styles. Instead, add `className` or extend the `style` prop. +4. **Performance Consideration**: Use `React.memo`, `useMemo`, or `useCallback` appropriately to prevent unnecessary re-rendering. +5. **Accessibility**: Consider accessibility (a11y) when creating custom components. For example, it's good to add appropriate `aria-` attributes to toggle buttons. +6. **Theme Support**: Design custom components to be compatible with React-Notion-Custom's theme system. Using CSS variables makes it easy to support theme switching, such as dark mode. + +## Applying Custom Components + +Here's how to use custom components in React-Notion-Custom: + +```jsx +import { Notion, type NotionPage, type CustomComponents } from 'react-notion-custom'; +import CustomParagraph from './CustomParagraph'; +import CustomToggle from './CustomToggle'; + +const MyNotionPage = ({ pageData }: { pageData: NotionPage }) => { + const customComponents = useMemo<CustomComponents>(() => ({ + paragraph: CustomParagraph, + toggle: CustomToggle, + }), []); + + return ( + <Notion custom={customComponents}> + <Notion.Cover cover={pageData.cover} /> + <Notion.Body> + <Notion.Title title={pageData.title} /> + <Notion.Blocks blocks={pageData.blocks} /> + </Notion.Body> + </Notion> + ); +}; +``` + +In this example, we pass custom components to the Notion component through the `custom` prop. + +By following these guidelines, you can extend the functionality of React-Notion-Custom while maintaining consistency and maintainability. diff --git a/packages/docs/content/guide/en/02. customization-guide/03. custom-style.md b/packages/docs/content/guide/en/02. customization-guide/03. custom-style.md new file mode 100644 index 0000000..7720288 --- /dev/null +++ b/packages/docs/content/guide/en/02. customization-guide/03. custom-style.md @@ -0,0 +1,168 @@ +--- +group: "customization-guide" +order: 3 +title: "CSS Structure and Styling Guide" +slug: "css-structure-and-styling" +description: "Understand the CSS structure of React-Notion-Custom and learn effective styling methods." +--- + +# CSS Structure and Styling Guide + +React-Notion-Custom provides a flexible and extensible CSS structure. This section explains the CSS variable system, key styling points, and the principles of indent application. + +## CSS Variable System + +React-Notion-Custom uses CSS variables to define global styles. This allows for easy theme changes and overall style adjustments. + +The main CSS variables are as follows: + +```css +.notion { + --notion-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, + "Segoe UI Emoji", "Segoe UI Symbol"; + --notion-max-width: 720px; + --notion-header-height: 45px; + --notion-indent: 27px; + + /* Color variables */ + --fg-color: rgb(55, 53, 47); + --fg-color-0: rgba(55, 53, 47, 0.09); + --fg-color-1: rgba(55, 53, 47, 0.16); + --fg-color-2: rgba(55, 53, 47, 0.4); + --fg-color-3: rgba(55, 53, 47, 0.6); + --fg-color-4: #000; + --fg-color-5: rgb(233, 233, 231); + --fg-color-6: rgba(55, 53, 47, 0.8); + --fg-color-icon: var(--fg-color); + + --bg-color: #fff; + --bg-color-0: rgba(135, 131, 120, 0.15); + --bg-color-1: rgb(247, 246, 243); + --bg-color-2: rgba(135, 131, 120, 0.15); + + --select-color-0: rgb(46, 170, 220); + --select-color-1: rgba(35, 131, 226, 0.28); + --select-color-2: #d9eff8; +} +``` + +You can easily change the overall style by redefining these variables. + +## Key Styling Points + +1. **Class Naming Convention**: All classes start with `notion-`. This prevents style conflicts. + + Example: `.notion-block`, `.notion-h1`, `.notion-toggle` + +2. **Block Level Styles**: The `notion-block` class is applied to all block-level elements. + + ```css + .notion-block { + display: block; + } + ``` + +3. **Color Application**: Colors are applied through CSS variables. + + ```css + .notion-text { + color: var(--fg-color); + } + ``` + +4. **Responsive Design**: The `--notion-max-width` variable is used to implement responsive layouts. + + ```css + .notion-body { + width: 100%; + max-width: var(--notion-max-width); + margin: 0 auto; + } + ``` + +## Indent Application Principle + +React-Notion-Custom implements indentation through a recursive structure. This is handled in CSS as follows: + +```css +.notion-block > .notion-block { + margin-left: var(--notion-indent); +} + +.notion-block > .notion-display-contents > .notion-block { + margin-left: var(--notion-indent); +} +``` + +This CSS rule automatically applies indentation to nested blocks. You can easily adjust the degree of indentation by modifying the `--notion-indent` variable. + +## Dark Mode and Custom Themes + +React-Notion-Custom supports dark mode by default. Dark mode is implemented as follows: + +```css +[data-theme="dark"] .notion { + --fg-color: rgba(255, 255, 255, 0.9); + --bg-color: #2f3437; + /* Other dark mode related variables... */ +} +``` + +Also, you can easily apply custom themes. You can apply the desired theme using the `data-theme` attribute: + +```jsx +<Notion data-theme="custom">{/* Notion content */}</Notion> +``` + +And you can define styles in CSS as follows: + +```css +.notion[data-theme="custom"] { + --fg-color: #333; + --bg-color: #f4f4f4; + /* Other custom theme related variables... */ +} +``` + +Using this method, you can easily override default styles by utilizing selector priority. + +## Style Customization Examples + +1. **Changing Global Font**: + + ```css + .notion[data-theme="custom"] { + --notion-font: "Roboto", sans-serif; + } + ``` + +2. **Changing Heading Styles**: + + ```css + .notion[data-theme="custom"] .notion-h1 { + font-size: 2.5em; + color: var(--select-color-0); + border-bottom: 2px solid var(--fg-color-1); + } + ``` + +3. **Adjusting Indentation**: + + ```css + .notion[data-theme="custom"] { + --notion-indent: 20px; + } + ``` + +4. **Implementing Dark Mode**: + + ```css + [data-theme="dark"] .notion[data-theme="custom"] { + --fg-color: rgba(255, 255, 255, 0.9); + --bg-color: #2f3437; + /* Adjust other color variables appropriately */ + } + ``` + +By following this CSS structure and styling guide, you can implement consistent and easily maintainable styles using React-Notion-Custom. Furthermore, detailed customization is possible as needed. diff --git a/packages/docs/content/guide/en/03. block-types/01. block-type-guide-intro.md b/packages/docs/content/guide/en/03. block-types/01. block-type-guide-intro.md new file mode 100644 index 0000000..811c71e --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/01. block-type-guide-intro.md @@ -0,0 +1,242 @@ +--- +group: "block-types" +order: 1 +title: "Introduction to Block Type Guide" +slug: "block-type-guide-intro" +description: "This guide introduces an overview of block types supported in React-Notion-Custom, their usage methods, customization options, and internal working principles." +--- + +# Introduction to Block Type Guide + +React-Notion-Custom supports various block types from Notion, providing components that closely resemble Notion's style for each block type. This guide explains the currently supported block types, the Props for each block type, customization methods, and internal working principles. + +## Supported Block Types + +Here's a list of block types currently supported and planned for support in React-Notion-Custom: + +| Block Type | Support Status | Block Type Enum | +| ------------------------ | -------------- | ---------------------- | +| Paragraph | ✅ Yes | `paragraph` | +| Heading 1 | ✅ Yes | `heading_1` | +| Heading 2 | ✅ Yes | `heading_2` | +| Heading 3 | ✅ Yes | `heading_3` | +| Bulleted List Item | ✅ Yes | `bulleted_list_item` | +| Numbered List Item | ✅ Yes | `numbered_list_item` | +| To-do | ❌ No | `to_do` | +| Toggle | ✅ Yes | `toggle` | +| Quote | ✅ Yes | `quote` | +| Callout | ✅ Yes | `callout` | +| Equation | ❌ No | `equation` | +| Code | ❌ No | `code` | +| Image | ❌ No | `image` | +| Video | ❌ No | `video` | +| Bookmark | ❌ No | `bookmark` | +| Divider | ✅ Yes | `divider` | +| Table | ❌ No | `table` | +| Table Row | ❌ No | `table_row` | +| Column | ❌ No | `column` | +| Column List | ❌ No | `column_list` | +| Audio | ❌ No | `audio` | +| Synced Block | ❌ No | `synced_block` | +| Table Of Contents | ❌ No | `table_of_contents` | +| Embed | ❌ No | `embed` | +| Figma | ❌ No | `figma` | +| Google Maps | ❌ No | `maps` | +| Google Drive | ❌ No | `drive` | +| Tweet | ❌ No | `tweet` | +| PDF | ❌ No | `pdf` | +| File | ❌ No | `file` | +| Link | ❌ No | `text` (inline) | +| Page Link | ❌ No | `page` | +| External Page Link | ❌ No | `text` (inline) | +| Collections | ❌ No | - | +| Collection View | ❌ No | `collection_view` | +| Collection View Table | ❌ No | `collection_view` | +| Collection View Gallery | ❌ No | `collection_view` | +| Collection View Board | ❌ No | `collection_view` | +| Collection View List | ❌ No | `collection_view` | +| Collection View Calendar | ❌ No | `collection_view` | +| Collection View Page | ❌ No | `collection_view_page` | + +This list will be continuously updated, and we plan to support more block types in the future. + +## Using Props + +React-Notion-Custom provides Props types for each block type. These Props types can be imported directly from the library for use. + +For example, the Props for the Paragraph component can be imported and used as follows: + +```typescript +import { ParagraphProps } from "react-notion-custom"; + +// Structure of ParagraphProps +interface ParagraphProps { + type: "paragraph"; + paragraph: { + rich_text: Array<RichTextItemResponse>; + color: string; + }; + id: string; + has_children?: boolean; +} + +// Usage example +const MyParagraph: React.FC<ParagraphProps> = (props) => { + // Custom implementation +}; +``` + +Detailed structures of Props for each block type can be found in the respective block type documentation. + +## Applying Custom Components + +One of the major advantages of React-Notion-Custom is the ability to completely replace each block type with custom components. Here's how to apply custom components: + +```jsx +import { Notion } from "react-notion-custom"; +import CustomParagraph from "./CustomParagraph"; +import CustomHeading from "./CustomHeading"; + +const customComponents = { + paragraph: CustomParagraph, + heading_1: CustomHeading, + heading_2: CustomHeading, + heading_3: CustomHeading, + // ... custom components for other block types +}; + +function MyNotionPage({ blocks }) { + return ( + <Notion custom={customComponents}> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +The type of `components` injected into the `Notion` component is as follows: + +```typescript +type NotionComponents = Record<string, React.ComponentType<any>>; +``` + +Here, `key` is the type of Notion block (e.g., 'paragraph', 'heading_1', etc.), and `value` is the React component that will render that type. + +## Data Preprocessing + +React-Notion-Custom preprocesses block data fetched from the Notion API into a form optimized for UI rendering. In this process, it defines and uses a new type called `ContextedBlock`. + +``` ++----------------------+ +| Notion API | +| Block Data | +| +------------------+ | +| | Block | | +| | - id | | +| | - type | | +| | - has_children | | +| | - [type_specific]| | +| +------------------+ | ++----------------------+ + | + | (Input) + v ++---------------------------+ +| resolveToContextedBlocks | +| +-------------------------+ +| | For each block: | +| | +---------------------+ | +| | |resolveToContextedBlo| | +| | |ck (recursive) | | +| | +---------------------+ | +| | | | +| | v | +| | Map parent-child | +| | relationships | +| +-------------------------+ +| | +| v +| Map sibling relationships | ++---------------------------+ + | + | (Output) + v ++---------------------------+ +| ContextedBlocks | +| +-------------------------+ +| | ContextedBlock | +| | - ...Block properties | +| | - context: | +| | - previous (sibling) | +| | - next (sibling) | +| | - parent | +| | - blocks (children) | +| +-------------------------+ ++---------------------------+ + | + | (Used by) + v + +----------------+ + | Notion.Blocks | + | Component | + +----------------+ +``` + +`ContextedBlock` extends the existing `Block` type to include the following additional information: + +- Previous block (sibling relationship) +- Next block (sibling relationship) +- Parent block + +This additional information can be useful in specific block components. + +## Rendering Process + +The rendering process of React-Notion-Custom is as follows: + +``` ++-------------------+ +------------------+ +| Custom | | Default | +| Components | | Components | ++-------------------+ +------------------+ + | | + | +-----------------+ | + +-->| Notion |<--+ + | Component | + |(React.Provider) | + +-----------------+ + | | + +----------+ +------------+ + | | ++----------------+ +----------------+ +| Notion.Cover | | Notion.Body | ++----------------+ +----------------+ + | + +----------------+ + | Notion.Title | + +----------------+ + | + +----------------+ + | Notion.Blocks | + +----------------+ + | + v + +----------------+ + | Rendered | + | Notion Page | + +----------------+ +``` + +Through this process, custom components and default components work together to render the Notion page. + +## Styling + +The currently provided Notion components are implemented to closely resemble Notion's style. Each component is styled using CSS classes with the `notion-` prefix. + +## Future Plans + +- Add support for more block types +- Develop component sets with applied themes +- Expand advanced customization options + +In the following pages, you can find detailed descriptions, Props structures, usage examples, and customization options for each block type. diff --git a/packages/docs/content/guide/en/03. block-types/02. heading.md b/packages/docs/content/guide/en/03. block-types/02. heading.md new file mode 100644 index 0000000..0b7c5cc --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/02. heading.md @@ -0,0 +1,124 @@ +--- +group: "block-types" +order: 3 +title: "Heading Block" +slug: "notion-block-heading" +description: "Detailed explanation of the Heading block type in React-Notion-Custom." +--- + +# Heading Block + +Heading blocks are used to represent the structure of a document and support three levels (Heading 1, Heading 2, Heading 3). + +## Data Structure + +The Notion API data structure for a Heading block is as follows (example for Heading 1): + +```json +{ + "type": "heading_1", + "heading_1": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a heading", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a heading", + "href": null + } + ], + "color": "default", + "is_toggleable": false + } +} +``` + +- `type`: Can be "heading_1", "heading_2", or "heading_3". +- `rich_text`: An array containing the content and style information of the heading text. +- `color`: Specifies the color of the heading. +- `is_toggleable`: Indicates whether the toggle feature is used. + +## React Component + +The component that renders the Heading block in React-Notion-Custom is as follows: + +```jsx +import React, { useMemo } from "react"; +import type { HeadingsProps, HeadingConfig } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +const Headings: React.FC<HeadingsProps> = ({ children, type, ...props }) => { + const { + [type]: { color, rich_text: texts, is_toggleable }, + } = props; + + const { headingTag: HeadingTag, headingClassName } = + useMemo<HeadingConfig>(() => { + switch (type) { + case "heading_2": + return { headingTag: "h2", headingClassName: "notion-h2" }; + case "heading_3": + return { headingTag: "h3", headingClassName: "notion-h3" }; + default: + return { headingTag: "h1", headingClassName: "notion-h1" }; + } + }, [type]); + + return ( + <div + className={`notion-block ${headingClassName} ${getColorCss(color)}`} + > + <HeadingTag className={`notion-h-content ${headingClassName}-content`}> + <RichText props={texts} /> + </HeadingTag> + {children} + </div> + ); +}; + +export default Headings; +``` + +## Usage Example + +Here's an example of how to use the Heading block: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +Here, `blocks` is an array of block data received from the Notion API. + +## Styling + +The style of the Heading block can be customized through the following CSS classes: + +- `.notion-block`: Basic style applied to all Notion blocks +- `.notion-h1`, `.notion-h2`, `.notion-h3`: Specific styles for each heading level +- `.notion-h1-content`, `.notion-h2-content`, `.notion-h3-content`: Styles for the content of each heading + +If additional styling is needed, you can write CSS targeting these classes. + +## Notes + +- As Heading blocks are important elements representing the structure of a document, it's recommended to use appropriate heading levels. +- If the `is_toggleable` property is true, the heading will have a toggle functionality. In this case, additional logic may be required. diff --git a/packages/docs/content/guide/en/03. block-types/03. bulleted-list-item.md b/packages/docs/content/guide/en/03. block-types/03. bulleted-list-item.md new file mode 100644 index 0000000..6df31b4 --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/03. bulleted-list-item.md @@ -0,0 +1,134 @@ +--- +group: "block-types" +order: 4 +title: "Bulleted List Item Block" +slug: "notion-block-bulleted-list-item" +description: "Detailed explanation of the Bulleted List Item block type in React-Notion-Custom." +--- + +# Bulleted List Item Block + +The Bulleted List Item block is used to create unordered lists. Each item starts with a bullet point. + +## Data Structure + +The Notion API data structure for a Bulleted List Item block is as follows: + +```json +{ + "type": "bulleted_list_item", + "bulleted_list_item": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a bulleted list item", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a bulleted list item", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: An array containing the text content and style information of the list item. +- `color`: Specifies the color of the text. + +## React Component + +The component that renders the Bulleted List Item block in React-Notion-Custom is as follows: + +```jsx +import React from "react"; +import type { BulletedListItemArgs } from "../types"; +import { bulletedListItemMarker, getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type BulletedListItemProps = { + children?: React.ReactNode; +} & BulletedListItemArgs; + +const BulletedListItem: React.FC<BulletedListItemProps> = ({ + children, + ...props +}) => { + const { + bulleted_list_item: { rich_text: texts, color }, + } = props; + const { marker, format } = bulletedListItemMarker.getMarker(props); + + return ( + <ul + data-notion-marker-format={format} + className={`notion-block notion-list-bulleted ${getColorCss(color)}`} + > + <li className="notion-display-contents"> + <div className="notion-list-bulleted-content"> + <span + data-notion-marker-format={format} + className="notion-list-marker" + > + {marker} + </span> + <p> + <RichText props={texts} /> + </p> + </div> + {children} + </li> + </ul> + ); +}; + +export default BulletedListItem; +``` + +## Usage Example + +Here's an example of how to use the Bulleted List Item block: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +Here, `blocks` is an array of block data received from the Notion API. + +## Styling + +The style of the Bulleted List Item block can be customized through the following CSS classes: + +- `.notion-block`: Basic style applied to all Notion blocks +- `.notion-list-bulleted`: Specific style for Bulleted List Item blocks +- `.notion-list-bulleted-content`: Style for the content of list items +- `.notion-list-marker`: Style for bullet points + +If additional styling is needed, you can write CSS targeting these classes. + +## Handling Nested Lists + +Bulleted List Items can be nested. Nested lists are handled through the `children` prop. The shape of the bullet point may change depending on the nesting level, which is handled by the `bulletedListItemMarker.getMarker` function. + +## Notes + +- When Bulleted List Item blocks are used consecutively, they are automatically grouped into a single list. +- When using nested lists, it's good to clearly express the hierarchical structure through appropriate indentation. +- The shape of the bullet points follows Notion's default style, but can be customized through CSS. diff --git a/packages/docs/content/guide/en/03. block-types/05. numbered-list-item.md b/packages/docs/content/guide/en/03. block-types/05. numbered-list-item.md new file mode 100644 index 0000000..82684bb --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/05. numbered-list-item.md @@ -0,0 +1,145 @@ +--- +group: "block-types" +order: 5 +title: "Numbered List Item Block" +slug: "numbered-list-item" +description: "Detailed explanation of the Numbered List Item block type in React-Notion-Custom." +--- + +# Numbered List Item Block + +The Numbered List Item block is used to create ordered lists. Each item starts with a sequential number. + +## Data Structure + +The Notion API data structure for a Numbered List Item block is as follows: + +```json +{ + "type": "numbered_list_item", + "numbered_list_item": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a numbered list item", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a numbered list item", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: An array containing the text content and style information of the list item. +- `color`: Specifies the color of the text. + +## React Component + +The component that renders the Numbered List Item block in React-Notion-Custom is as follows: + +```jsx +import React from "react"; +import type { NumberedListItemArgs } from "../types"; +import { getColorCss, numberedListItemMarker } from "../utils"; +import RichText from "./internal/rich-text"; + +type NumberedListProps = { + children?: React.ReactNode; +} & NumberedListItemArgs; + +const NumberedListItem: React.FC<NumberedListProps> = ({ + children, + ...props +}) => { + const { + numbered_list_item: { rich_text: texts, color }, + } = props; + const { marker, format } = numberedListItemMarker.getMarker(props); + + return ( + <ol + data-notion-marker-format={format} + className={`notion-block notion-list-numbered ${getColorCss(color)}`} + > + <li className="notion-display-contents"> + <div className="notion-list-numbered-content"> + <span + data-notion-marker-format={format} + className="notion-list-marker" + > + {marker} + </span> + <p> + <RichText props={texts} /> + </p> + </div> + {children} + </li> + </ol> + ); +}; + +export default NumberedListItem; +``` + +## Usage Example + +Here's an example of how to use the Numbered List Item block: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +Here, `blocks` is an array of block data received from the Notion API. + +## Styling + +The style of the Numbered List Item block can be customized through the following CSS classes: + +- `.notion-block`: Basic style applied to all Notion blocks +- `.notion-list-numbered`: Specific style for Numbered List Item blocks +- `.notion-list-numbered-content`: Style for the content of list items +- `.notion-list-marker`: Style for numbers + +If additional styling is needed, you can write CSS targeting these classes. + +## Numbering System + +The numbering system for Numbered List Items is determined by the `numberedListItemMarker.getMarker` function. This function returns an appropriate number or character considering the current item's position and nesting level. By default, it follows this order: + +1. Top level: 1, 2, 3, ... +2. Second level: a, b, c, ... +3. Third level: i, ii, iii, ... + +This order can be customized as needed. + +## Handling Nested Lists + +Numbered List Items can also be nested. Nested lists are handled through the `children` prop. The numbering system may change depending on the nesting level, which is handled by the `numberedListItemMarker.getMarker` function. + +## Notes + +- When Numbered List Item blocks are used consecutively, they are automatically grouped into a single list. +- When using nested lists, it's good to clearly express the hierarchical structure through appropriate indentation. +- The numbering system follows Notion's default style, but can be customized through CSS. +- If a list is interrupted and then resumed, the numbering may start over, so care should be taken. diff --git a/packages/docs/content/guide/en/03. block-types/06. Quote.md b/packages/docs/content/guide/en/03. block-types/06. Quote.md new file mode 100644 index 0000000..dda363e --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/06. Quote.md @@ -0,0 +1,136 @@ +--- +group: "block-types" +order: 6 +title: "Quote Block" +slug: "quote" +description: "Detailed explanation of the Quote block type in React-Notion-Custom." +--- + +# Quote Block + +The Quote block is used to display text quoted from another source. It is typically represented in a visually distinct style. + +## Data Structure + +The Notion API data structure for a Quote block is as follows: + +```json +{ + "type": "quote", + "quote": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a quote", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a quote", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: An array containing the text content and style information of the quote. +- `color`: Specifies the color of the quote. + +## React Component + +The component that renders the Quote block in React-Notion-Custom is as follows: + +```jsx +import React from "react"; +import type { QuoteArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type QuoteProps = { + children?: React.ReactNode; +} & QuoteArgs; + +const Quote: React.FC<QuoteProps> = ({ children, ...props }) => { + const { + quote: { color, rich_text: texts }, + } = props; + + return ( + <div className={`notion-block notion-quote ${getColorCss(color)}`}> + <div className="notion-quote-content"> + <p> + <RichText props={texts} /> + </p> + {children} + </div> + </div> + ); +}; + +export default Quote; +``` + +## Usage Example + +Here's an example of how to use the Quote block: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +Here, `blocks` is an array of block data received from the Notion API. + +## Styling + +The style of the Quote block can be customized through the following CSS classes: + +- `.notion-block`: Basic style applied to all Notion blocks +- `.notion-quote`: Specific style for Quote blocks +- `.notion-quote-content`: Style for the content of the quote + +If additional styling is needed, you can write CSS targeting these classes. Typically, Quote blocks have the following style characteristics: + +- Thick border on the left or both sides +- Slight indentation +- Changed background color +- Changed font style (e.g., italics) + +For example, you can apply the following CSS: + +```css +.notion-quote { + border-left: 4px solid #ccc; + padding-left: 16px; + margin-left: 0; + margin-right: 0; + font-style: italic; + background-color: #f9f9f9; +} +``` + +## Nesting Support + +Quote blocks can contain other blocks. This is handled through the `children` prop. For example, you can include lists or other text blocks within a quote. + +## Notes + +- Quote blocks are generally used for short quotations. For longer quotes, it might be better to split them into multiple Quote blocks for readability. +- It's good practice to specify the source of the quote. This can be added as a separate Paragraph block below the Quote block. +- For accessibility, it's recommended to add appropriate ARIA attributes for screen reader users. For example, you can use the `role="blockquote"` attribute. diff --git a/packages/docs/content/guide/en/03. block-types/07. Paragraph.md b/packages/docs/content/guide/en/03. block-types/07. Paragraph.md new file mode 100644 index 0000000..8d2cdce --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/07. Paragraph.md @@ -0,0 +1,106 @@ +--- +group: "block-types" +order: 2 +title: "Paragraph Block" +slug: "paragraph" +description: "Detailed explanation of the Paragraph block type in React-Notion-Custom." +--- + +# Paragraph Block + +The Paragraph block is the most basic block type used to represent plain text. + +## Data Structure + +The Notion API data structure for a Paragraph block is as follows: + +```json +{ + "type": "paragraph", + "paragraph": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a paragraph.", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a paragraph.", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: An array containing the content and style information of the text. +- `color`: Specifies the color of the text. + +## React Component + +The component that renders the Paragraph block in React-Notion-Custom is as follows: + +```jsx +import React from "react"; +import type { ParagraphArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type ParagraphProps = { + children?: React.ReactNode; +} & ParagraphArgs; + +const Paragraph: React.FC<ParagraphProps> = ({ children, ...props }) => { + const { + paragraph: { color, rich_text: texts }, + } = props; + + return ( + <div className={`notion-block notion-paragraph ${getColorCss(color)}`}> + <p className="notion-paragraph-content"> + <RichText props={texts} /> + </p> + {children} + </div> + ); +}; + +export default Paragraph; +``` + +## Usage Example + +Here's an example of how to use the Paragraph block: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +Here, `blocks` is an array of block data received from the Notion API. + +## Styling + +The style of the Paragraph block can be customized through the following CSS classes: + +- `.notion-block`: Basic style applied to all Notion blocks +- `.notion-paragraph`: Specific style for Paragraph blocks +- `.notion-paragraph-content`: Style for the content of the paragraph + +If additional styling is needed, you can write CSS targeting these classes. diff --git a/packages/docs/content/guide/en/03. block-types/08. Callout.md b/packages/docs/content/guide/en/03. block-types/08. Callout.md new file mode 100644 index 0000000..0901433 --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/08. Callout.md @@ -0,0 +1,155 @@ +--- +group: "block-types" +order: 7 +title: "Callout Block" +slug: "callout" +description: "Detailed explanation of the Callout block type in React-Notion-Custom." +--- + +# Callout Block + +The Callout block is used to emphasize content that needs attention. It's typically displayed with an icon and a colored background to make it visually stand out. + +## Data Structure + +The Notion API data structure for a Callout block is as follows: + +```json +{ + "type": "callout", + "callout": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a callout", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a callout", + "href": null + } + ], + "icon": { + "type": "emoji", + "emoji": "💡" + }, + "color": "gray_background" + } +} +``` + +- `rich_text`: An array containing the text content and style information of the callout. +- `icon`: Information about the icon to be displayed with the callout. It can be an emoji or an external image URL. +- `color`: Specifies the background color of the callout. + +## React Component + +The component that renders the Callout block in React-Notion-Custom is as follows: + +```jsx +import React from "react"; +import type { CalloutArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; +import Icon from "./internal/icon"; + +type CalloutProps = { + children?: React.ReactNode; +} & CalloutArgs; + +const Callout: React.FC<CalloutProps> = ({ children, ...props }) => { + const { callout } = props; + + return ( + <div + className={`notion-block notion-callout ${getColorCss(callout.color)}`} + > + <div className="notion-callout-content"> + <div className="notion-callout-icon" aria-hidden="true"> + <Icon icon={callout.icon} /> + </div> + <div className="notion-callout-text"> + <RichText props={callout.rich_text} /> + </div> + </div> + {children} + </div> + ); +}; + +export default Callout; +``` + +## Usage Example + +Here's an example of how to use the Callout block: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +Here, `blocks` is an array of block data received from the Notion API. + +## Icon Handling + +The icon for the Callout block is handled through the `Icon` component. This component supports both emojis and external image URLs. It selects the appropriate rendering method based on the icon type. + +## Styling + +The style of the Callout block can be customized through the following CSS classes: + +- `.notion-block`: Basic style applied to all Notion blocks +- `.notion-callout`: Specific style for Callout blocks +- `.notion-callout-content`: Style for the content of the callout +- `.notion-callout-icon`: Style for the callout icon +- `.notion-callout-text`: Style for the callout text + +If additional styling is needed, you can write CSS targeting these classes. For example: + +```css +.notion-callout { + border-radius: 4px; + padding: 16px; + display: flex; + align-items: center; +} + +.notion-callout-icon { + margin-right: 12px; + font-size: 24px; +} + +.notion-callout-text { + flex: 1; +} +``` + +## Color Handling + +The `color` property of the Callout determines the background color. The `getColorCss` utility function is used to generate the appropriate CSS class. This function converts Notion's color names into CSS classes. + +## Nesting Support + +Callout blocks can contain other blocks. This is handled through the `children` prop. For example, you can include lists or other text blocks within a callout. + +## Notes + +- Callout blocks are effective for emphasizing important information or warnings. However, excessive use can be distracting, so they should be used appropriately. +- Make sure the combination of icon and background color meets accessibility standards. In particular, maintain sufficient contrast between text and background. +- It's good practice to provide appropriate alternative text for icons to support screen reader users. diff --git a/packages/docs/content/guide/en/03. block-types/09. Toggle.md b/packages/docs/content/guide/en/03. block-types/09. Toggle.md new file mode 100644 index 0000000..1bee0f2 --- /dev/null +++ b/packages/docs/content/guide/en/03. block-types/09. Toggle.md @@ -0,0 +1,179 @@ +--- +group: "block-types" +order: 8 +title: "Toggle Block" +slug: "toggle" +description: "Detailed explanation of the Toggle block type in React-Notion-Custom." +--- + +# Toggle Block + +The Toggle block is used to create collapsible content. It's an interactive element where hidden content expands or collapses when the user clicks on the toggle. + +## Data Structure + +The Notion API data structure for a Toggle block is as follows: + +```json +{ + "type": "toggle", + "toggle": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "Click to toggle", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Click to toggle", + "href": null + } + ], + "color": "default", + "children": [ + // Nested blocks... + ] + } +} +``` + +- `rich_text`: An array containing the display text and style information of the toggle. +- `color`: Specifies the color of the toggle text. +- `children`: An array of nested blocks that will be displayed when the toggle is expanded. + +## React Component + +The component that renders the Toggle block in React-Notion-Custom is as follows: + +```jsx +import React, { useState, useCallback } from "react"; +import type { ToggleArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type ToggleProps = { + children?: React.ReactNode; +} & ToggleArgs; + +const Toggle: React.FC<ToggleProps> = ({ children, ...props }) => { + const { + toggle: { color, rich_text: texts }, + } = props; + + const [open, setOpen] = useState(false); + + const toggleOpen = useCallback(() => setOpen((prevOpen) => !prevOpen), []); + + return ( + <div + className={`notion-block notion-toggle ${getColorCss(color)} ${ + open ? "notion-toggle-open" : "" + }`} + aria-expanded={open} + > + <div className="notion-toggle-content"> + <button onClick={toggleOpen} className="notion-toggle-button"> + <div + className={`notion-toggle-button-arrow ${ + open ? "notion-toggle-button-arrow-opened" : "" + }`} + /> + </button> + <p> + <RichText props={texts} /> + </p> + </div> + + {open && children} + </div> + ); +}; + +export default Toggle; +``` + +## Usage Example + +Here's an example of how to use the Toggle block: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +Here, `blocks` is an array of block data received from the Notion API. + +## State Management + +The Toggle block internally uses the `useState` hook to manage its open/closed state. The `open` state variable represents the current state of the toggle, and the `toggleOpen` function switches this state. + +## Styling + +The style of the Toggle block can be customized through the following CSS classes: + +- `.notion-block`: Basic style applied to all Notion blocks +- `.notion-toggle`: Specific style for Toggle blocks +- `.notion-toggle-open`: Style for when the toggle is in the open state +- `.notion-toggle-content`: Style for the toggle content +- `.notion-toggle-button`: Style for the toggle button +- `.notion-toggle-button-arrow`: Style for the toggle arrow + +If additional styling is needed, you can write CSS targeting these classes. For example: + +```css +.notion-toggle { + margin-bottom: 8px; +} + +.notion-toggle-button { + cursor: pointer; + background: none; + border: none; + padding: 0; + margin-right: 4px; +} + +.notion-toggle-button-arrow { + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #333; + transition: transform 0.3s ease; +} + +.notion-toggle-button-arrow-opened { + transform: rotate(180deg); +} +``` + +## Nesting Support + +Toggle blocks can contain other blocks. This is handled through the `children` prop. The `children` are only rendered when the toggle is in the open state. + +## Accessibility Considerations + +- The `aria-expanded` attribute is used to inform screen readers of the toggle's current state. +- It's good to add `tabIndex={0}` to the toggle button to support keyboard navigation. +- Providing an appropriate `aria-label` to the toggle button is recommended to clearly describe its function. + +## Notes + +- Including too much content inside a toggle can degrade the user experience, so it's best to include only an appropriate amount of content. +- The open/closed state of toggles is not stored on the server, so all toggles will return to their default state (closed) when the page is refreshed. +- Deeply nested toggles can confuse users, so it's best to limit the nesting levels as much as possible. diff --git a/packages/docs/content/guide/kr/01. getting-started/01. introduction.md b/packages/docs/content/guide/kr/01. getting-started/01. introduction.md new file mode 100644 index 0000000..25c08ef --- /dev/null +++ b/packages/docs/content/guide/kr/01. getting-started/01. introduction.md @@ -0,0 +1,102 @@ +--- +group: "getting-started" +order: 1 +title: "프로젝트 소개" +slug: "introduction" +description: "React-Notion-Custom 프로젝트의 개요, 주요 기능, 그리고 활용 가능성에 대해 소개합니다." +--- + +# React-Notion-Custom 프로젝트 소개 + +## React-Notion-Custom이란? + +React-Notion-Custom은 Notion의 강력한 콘텐츠 작성 기능을 웹사이트로 손쉽게 가져올 수 있게 해주는 도구입니다. 이 라이브러리를 사용하면 Notion에서 작성한 콘텐츠를 그대로 React 기반의 웹사이트에서 렌더링할 수 있습니다. 개발자에게는 빠르게 결과를 만들어낼 수 있는 도구가 되고, 콘텐츠 작성자에게는 편리한 관리 도구가 되는, 그야말로 "개발자와 작성자 모두를 위한 매직 포션" 같은 존재입니다. ✨ + +## 주요 기능 및 제공하는 가치 + +### 🛠️ Notion 데이터의 React 렌더링 + +Notion에서 작성한 글, 이미지, 리스트, 코드 블록 등 다양한 콘텐츠를 React 컴포넌트로 쉽게 변환할 수 있습니다. 다음과 같은 구조로 Notion 페이지가 웹에서 재탄생합니다: + +```jsx +import { Notion, type NotionPageData } from 'react-notion-custom'; + +interface NotionPageProps { + pageData: NotionPageData; +} + +function NotionPage({ pageData }: NotionPageProps) { + return ( + <Notion> + <Notion.Cover src={pageData.cover} /> + <Notion.Body> + <Notion.Title title={pageData.title} /> + <Notion.Blocks blocks={pageData.blocks} /> + </Notion.Body> + </Notion> + ); +} +``` + +이 예제에서 `NotionPageData` 타입은 Notion 페이지의 데이터 구조를 정의합니다. 이를 통해 TypeScript의 타입 체크 기능을 활용하여 더 안정적인 코드를 작성할 수 있습니다. + +### 🎨 커스터마이징의 자유 + +CSS만 건드려서 간단하게 테마를 바꾸거나, 기본 제공 컴포넌트를 부분적으로 수정해 필요한 부분만 커스터마이징할 수 있습니다. 심지어 완전히 새로운 컴포넌트를 만들어 React-Notion-Custom에 결합할 수도 있어요. 코드를 다루는 개발자에게는 무한한 가능성을 제공합니다. + +### 🚀 빠른 사이트 구축 + +Notion-dump CLI를 사용해 Notion 데이터를 쉽게 추출하고, Next.js와 같은 프레임워크를 통해 빠르게 정적 사이트를 구축할 수 있습니다. 몇 가지 명령어만으로 사이트를 구축하는 과정은 마치 텍스트에서 바로 웹사이트가 완성되는 느낌을 줍니다. + +```bash +npx notion-dump --page YOUR_PAGE_URL --auth YOUR_API_KEY +``` + +notion-dump를 실행하면 다음과 같은 폴더 구조로 Notion 데이터가 추출됩니다: + +``` +my-notion-project/ +├── notion-data/ +│ ├── page-id-1.json +│ ├── page-id-2.json +│ └── ... +└── public/ + └── notion-dadta/ + ├── page-id-1/ + │ ├── image1.png + │ └── image2.jpg + ├── page-id-2/ + │ └── image1.png + └── ... +``` + +- `notion-data/`: 각 Notion 페이지의 내용이 JSON 형식으로 저장됩니다. 파일명은 페이지의 slug를 기반으로 생성됩니다. +- `public/notion-data/`: Notion 페이지에서 사용된 이미지들이 각 페이지별로 분류되어 저장됩니다. + +이렇게 추출된 데이터는 React-Notion-Custom 컴포넌트와 쉽게 연동되어, Notion의 콘텐츠를 빠르게 웹사이트로 변환할 수 있습니다. JSON 파일의 내용을 React 컴포넌트에 전달하기만 하면, Notion 페이지의 구조와 스타일이 그대로 웹사이트에 반영됩니다. + +## 타겟 사용자와 그들의 활용 가능성 + +### 개발자 + +Notion에서 작성한 콘텐츠를 웹사이트에 쉽게 렌더링하고, 커스터마이징할 수 있는 자유가 주어집니다. 빠르게 웹사이트를 구축하고 싶거나, 상용 서비스의 한계를 넘어 원하는 스타일로 꾸미고 싶다면 React-Notion-Custom이 답입니다. + +### 디자이너 및 크리에이터 + +Notion에서 작성한 콘텐츠를 직접 웹에 반영할 수 있어 디자인에 일관성을 유지하면서 빠르게 콘텐츠를 업데이트할 수 있습니다. + +### 활용 가능성 예시 + +- **개인 블로그**: Notion에서 쉽게 글을 작성하고, 자동으로 웹사이트에 반영합니다. +- **회사 소개 및 채용 페이지**: Notion을 활용해 회사 프로필이나 채용 정보를 빠르게 업데이트할 수 있습니다. +- **포트폴리오 사이트**: 프로젝트와 작업물을 손쉽게 업데이트할 수 있어, 포트폴리오 관리가 한결 쉬워집니다. + +## React-Notion-Custom을 선택해야 하는 이유 + +1. **개발자 중심의 커스터마이징**: 다른 상용 서비스에서는 손댈 수 없는 세밀한 부분까지 수정할 수 있습니다. 코드를 통한 무한한 가능성, 이것이 React-Notion-Custom의 매력입니다. + +2. **오픈소스의 자유**: 모든 것이 투명하고, 여러분의 손에서 직접 다룰 수 있습니다. 필요하면 코드를 수정하고, 프로젝트를 자신의 서버에서 셀프 호스팅할 수 있어 비용 부담도 없습니다. + +3. **빠른 결과와 높은 효율성**: Notion에서 콘텐츠를 작성하고, 간단한 설정만으로 웹사이트에서 바로 사용할 수 있습니다. 콘텐츠 작성과 배포의 과정이 한층 더 간소화됩니다. + +React-Notion-Custom은 여러분의 Notion 페이지를 멋진 웹사이트로 바꾸는 다리입니다. 이제 복잡한 설정은 그만, Notion에서 바로 시작해 보세요! diff --git a/packages/docs/content/guide/kr/01. getting-started/02. quick-start.md b/packages/docs/content/guide/kr/01. getting-started/02. quick-start.md new file mode 100644 index 0000000..56fd351 --- /dev/null +++ b/packages/docs/content/guide/kr/01. getting-started/02. quick-start.md @@ -0,0 +1,216 @@ +--- +group: "getting-started" +order: 2 +title: "빠른 시작 가이드" +slug: "quick-start" +description: "React-Notion-Custom을 사용하여 Notion 콘텐츠를 웹사이트로 구축하는 과정을 단계별로 안내합니다." +--- + +# React-Notion-Custom 빠른 시작 가이드 + +## 2.1. 설치 및 셋업 + +### React-Notion-Custom 설치 + +React-Notion-Custom과 Notion 데이터를 추출할 CLI 도구인 Notion-dump를 설치합니다. + +```bash +npm install react-notion-custom notion-dump +``` + +### Next.js 프로젝트 설정 + +Next.js 프로젝트가 없는 경우 새로 생성합니다. Next.js는 정적 사이트 생성과 서버사이드 렌더링을 지원하여 최적의 성능을 제공합니다. + +```bash +npx create-next-app my-notion-blog +cd my-notion-blog +``` + +### Notion API 키 생성 + +1. Notion 개발자 포털(https://developers.notion.com/)에 접속합니다. +2. 새 통합(integration)을 생성합니다. +3. 생성된 API 키를 안전하게 보관합니다. + +## 2.2. Notion 데이터 추출하기 (notion-dump) + +Notion-dump CLI를 사용하여 Notion 데이터를 JSON 형식으로 추출하고, 이를 웹사이트에 사용할 수 있도록 준비합니다. + +### 데이터 추출 명령어 사용법 + +Notion 페이지 URL과 API 키를 사용해 데이터를 추출합니다. + +```bash +npx notion-dump --page YOUR_PAGE_URL --auth YOUR_API_KEY +``` + +### notion-dump 폴더 구조 및 옵션 + +notion-dump는 기본적으로 Next.js 프로젝트 구조에 맞춰져 있습니다. 추출된 데이터는 다음과 같은 구조로 저장됩니다: + +``` +my-notion-blog/ +├── notion-data/ +│ ├── page-id-1.json +│ ├── page-id-2.json +│ └── ... +└── public/ + └── images/ + ├── page-id-1/ + │ ├── image1.png + │ └── image2.jpg + ├── page-id-2/ + │ └── image1.png + └── ... +``` + +notion-dump의 주요 옵션: + +- `--dir`: JSON 파일이 저장될 디렉토리를 지정합니다. 기본값은 `./notion-data`입니다. +- `--image-dir`: 이미지 파일이 저장될 디렉토리를 지정합니다. 기본값은 `./public/images`입니다. + +예를 들어, 저장 위치를 변경하고 싶다면 다음과 같이 사용할 수 있습니다: + +```bash +npx notion-dump --page YOUR_PAGE_URL --auth YOUR_API_KEY --dir ./data --image-dir ./public/assets/images +``` + +옵션을 지정하지 않으면 기본값이 사용되며, 이는 Next.js 프로젝트 구조에 최적화되어 있습니다. + +## 2.3. React에서 Notion 데이터 렌더링 + +추출한 Notion 데이터를 React 컴포넌트를 사용하여 렌더링합니다. 이 단계에서는 기본적인 페이지 구조와 컴포넌트 사용법을 다룹니다. + +### 기본 렌더링 예제 코드 + +Notion 데이터를 React 컴포넌트로 렌더링하는 간단한 예제입니다. + +```jsx +import { Notion } from "react-notion-custom"; +import pageData from "./notion-data/your-page-id.json"; + +function NotionPage() { + return ( + <Notion data={pageData}> + <Notion.Cover src={pageData.cover} /> + <Notion.Body> + <Notion.Title title={pageData.title} /> + <Notion.Blocks blocks={pageData.blocks} /> + </Notion.Body> + </Notion> + ); +} + +export default NotionPage; +``` + +### 설명 + +- `<Notion>` 컴포넌트는 Notion 데이터를 받아 페이지를 구성합니다. +- `<Cover>`, `<Title>`, `<Blocks>` 등 Notion의 기본 요소를 그대로 웹에서 표현할 수 있습니다. + +## 2.4. Next.js 통합으로 첫 페이지 만들기 + +Next.js를 통해 동적 웹페이지를 생성하고, 정적 사이트 생성(SSG)을 활용해 성능을 최적화합니다. + +### Next.js 페이지 생성 및 동적 라우팅 설정 + +각 포스트 페이지를 동적 라우팅으로 생성하고, 정적 사이트 생성을 위해 `getStaticPaths`와 `getStaticProps`를 사용합니다. + +```jsx +// pages/[slug].js +import { Notion } from "react-notion-custom"; +import posts from "../posts"; + +export async function getStaticPaths() { + const paths = posts.map((post) => ({ + params: { slug: post.slug }, + })); + return { paths, fallback: false }; +} + +export async function getStaticProps({ params }) { + const post = posts.find((p) => p.slug === params.slug); + return { props: { post } }; +} + +export default function PostPage({ post }) { + return ( + <Notion> + <Notion.Blocks blocks={post.content.blocks} /> + </Notion> + ); +} +``` + +### 설명 + +- `getStaticPaths`는 포스트의 경로를 미리 생성합니다. +- `getStaticProps`는 각 포스트의 데이터를 받아와 렌더링합니다. + +## 2.5. 블로그 만들기 + +이 섹션에서는 블로그의 전체 구조를 설정하고, 각 포스트를 어떻게 관리하고 표시할 수 있는지에 대해 설명합니다. + +### posts/index.js 설정 + +블로그 포스트 데이터를 중앙에서 관리합니다. 각 포스트의 메타데이터와 콘텐츠를 배열로 정리하여 사용합니다. + +```javascript +// posts/index.js +import post1Content from "../notion-data/post1.json"; +import post2Content from "../notion-data/post2.json"; + +const posts = [ + { + slug: "post1", + title: "첫 번째 블로그 포스트", + date: "2023-10-01", + description: "첫 번째 블로그 포스트의 설명입니다.", + content: post1Content, + }, + { + slug: "post2", + title: "두 번째 블로그 포스트", + date: "2023-10-05", + description: "두 번째 블로그 포스트의 설명입니다.", + content: post2Content, + }, +]; + +export default posts; +``` + +### 데이터 사용하기: 블로그 메인 페이지 + +`posts` 배열을 사용하여 메인 페이지에서 포스트 목록을 렌더링합니다. + +```jsx +// pages/index.js +import Link from "next/link"; +import posts from "../posts"; + +export default function Home() { + return ( + <div> + <h1>블로그 포스트 목록</h1> + <ul> + {posts.map((post) => ( + <li key={post.slug}> + <Link href={`/${post.slug}`}> + <a>{post.title}</a> + </Link> + <p>{post.description}</p> + <small>{post.date}</small> + </li> + ))} + </ul> + </div> + ); +} +``` + +### 개별 포스트 페이지 생성 + +각 포스트 페이지는 동적 라우팅을 통해 자동 생성됩니다. Notion에서 작성한 글이 그대로 웹사이트에 반영되어, 블로그를 손쉽게 업데이트할 수 있습니다. diff --git a/packages/docs/content/guide/kr/02. customization-guide/01. structure-and-customization.md b/packages/docs/content/guide/kr/02. customization-guide/01. structure-and-customization.md new file mode 100644 index 0000000..06af0f8 --- /dev/null +++ b/packages/docs/content/guide/kr/02. customization-guide/01. structure-and-customization.md @@ -0,0 +1,175 @@ +--- +group: "customization-guide" +order: 1 +title: "React-Notion-Custom 구조 이해와 커스터마이징" +slug: "structure-and-customization" +description: "React-Notion-Custom의 데이터 구조를 이해하고 이를 바탕으로 효과적인 커스터마이징 방법을 학습합니다." +--- + +# React-Notion-Custom 구조 이해와 커스터마이징 + +React-Notion-Custom을 효과적으로 커스터마이징하기 위해서는 먼저 기본 구조와 데이터 흐름을 이해해야 합니다. 이 섹션에서는 Notion 데이터의 구조를 살펴보고, 이를 바탕으로 커스텀 컴포넌트를 만드는 방법을 설명합니다. + +## 데이터 구조 이해하기 + +React-Notion-Custom이 사용하는 Notion 데이터는 JSON 형식으로 구성되며, 페이지 정보와 각 블록의 세부 내용을 포함합니다. 이 구조를 이해하는 것이 효과적인 커스터마이징의 첫 걸음입니다. + +### 기본 데이터 구조 + +```json +{ + "object": "page", + "id": "page-id", + "created_time": "2024-09-20T13:54:00.000Z", + "last_edited_time": "2024-09-21T04:28:00.000Z", + "cover": null, + "icon": null, + "parent": { + "type": "page_id", + "page_id": "parent-page-id" + }, + "properties": { + "title": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "페이지 제목", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "color": "default" + }, + "plain_text": "페이지 제목" + } + ] + } + }, + "blocks": [ + { + "object": "block", + "id": "block-id-1", + "type": "toggle", + "toggle": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "토글 내용", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "color": "default" + }, + "plain_text": "토글 내용" + } + ], + "color": "default" + }, + "blocks": [ + { + "object": "block", + "id": "block-id-2", + "type": "paragraph", + "paragraph": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "토글 내부 단락", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "color": "default" + }, + "plain_text": "토글 내부 단락" + } + ], + "color": "default" + } + } + ] + } + ] +} +``` + +### 주요 구조 요소 + +1. **페이지 메타데이터**: `id`, `created_time`, `last_edited_time`, `parent` 등 페이지의 기본 정보를 포함합니다. + +2. **cover와 icon**: 페이지의 커버 이미지와 아이콘 정보입니다. 커스텀 디자인을 적용할 때 이 정보를 활용할 수 있습니다. + +3. **properties**: 페이지의 속성 정보로, 주로 페이지 제목(`title`)이 포함됩니다. 커스텀 헤더를 만들 때 이 정보를 사용할 수 있습니다. + +4. **blocks**: 페이지 내용을 구성하는 블록들의 배열입니다. 각 블록은 다음 구조를 가집니다: + + - `object`: 항상 "block" + - `id`: 블록의 고유 식별자 + - `type`: 블록의 타입 (예: "toggle", "paragraph", "heading_1" 등) + - `[type]`: 블록 타입에 해당하는 키로, 해당 블록의 구체적인 내용을 포함합니다. + - `blocks`: 하위 블록들의 배열. 이를 통해 재귀적인 구조를 형성합니다. + +5. **재귀적 구조**: `blocks` 배열 내의 각 블록은 다시 `blocks` 배열을 가질 수 있어, 중첩된 구조를 표현할 수 있습니다. 이는 토글, 목록 등의 중첩된 콘텐츠를 커스터마이징할 때 중요합니다. + +6. **rich_text**: 대부분의 텍스트 콘텐츠는 `rich_text` 배열로 표현되며, 텍스트의 스타일 정보(`annotations`)를 포함합니다. 이를 통해 텍스트 스타일을 세밀하게 커스터마이징할 수 있습니다. + +## 커스터마이징을 위한 컴포넌트 구조 + +React-Notion-Custom의 기본적인 컴포넌트 구조는 다음과 같습니다: + +<pre style="font-family: monospace; line-height: 1.2; white-space: pre;"> +┌────────────────────────────────────────────────────────────────┐ +│ <Notion> │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ <Cover /> │ │ +│ │ // Page cover image │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────┐ │ +│ │ <Body> │ │ +│ │ ┌──────────────────────┐ │ │ +│ │ │ <Title /> │ │ │ +│ │ │ // Page title │ │ │ +│ │ └──────────────────────┘ │ │ +│ │ ┌──────────────────────┐ │ │ +│ │ │ <Blocks> │ │ │ +│ │ │ ┌──────────────────┐ │ │ │ +│ │ │ │<Block type="...">│ │ │ │ +│ │ │ │ // e.g. Heading │ │ │ │ +│ │ │ └──────────────────┘ │ │ │ +│ │ │ ┌──────────────────┐ │ │ │ +│ │ │ │<Block type="...">│ │ │ │ +│ │ │ │ // e.g. Para │ │ │ │ +│ │ │ └──────────────────┘ │ │ │ +│ │ │ ... │ │ │ +│ │ │ // More blocks │ │ │ +│ │ └──────────────────────┘ │ │ +│ └────────────────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────┘ +</pre> + +이 구조에서 `<Body>` 컴포넌트는 전체 너비의 약 60%를 차지하며 중앙에 정렬됩니다. 이 레이아웃을 기반으로 각 컴포넌트를 커스터마이징할 수 있습니다. + +## 커스터마이징 전략 + +1. **블록별 커스텀 컴포넌트**: 각 블록 타입(`paragraph`, `heading_1`, `toggle` 등)에 대해 커스텀 컴포넌트를 만들어 기본 스타일과 동작을 오버라이드할 수 있습니다. + +2. **스타일 커스터마이징**: CSS 변수와 클래스를 활용하여 전체적인 디자인을 조정할 수 있습니다. + +3. **레이아웃 수정**: `<Body>` 컴포넌트의 너비나 정렬을 조정하여 전체 레이아웃을 변경할 수 있습니다. + +4. **재귀적 렌더링 활용**: 중첩된 블록 구조를 활용하여 복잡한 레이아웃이나 인터랙션을 구현할 수 있습니다. + +5. **메타데이터 활용**: 페이지의 메타데이터, 커버 이미지, 아이콘 등을 활용하여 풍부한 UI를 구성할 수 있습니다. + +이러한 구조와 전략을 이해하면, React-Notion-Custom을 기반으로 고도로 커스터마이즈된 Notion 기반 웹사이트를 만들 수 있습니다. 다음 섹션에서는 각 요소별 구체적인 커스터마이징 방법을 살펴보겠습니다. diff --git a/packages/docs/content/guide/kr/02. customization-guide/02. custom-component.md b/packages/docs/content/guide/kr/02. customization-guide/02. custom-component.md new file mode 100644 index 0000000..4ff809c --- /dev/null +++ b/packages/docs/content/guide/kr/02. customization-guide/02. custom-component.md @@ -0,0 +1,215 @@ +--- +group: "customization-guide" +order: 2 +title: "커스텀 컴포넌트 사용법" +slug: "custom-component-usage" +description: "React-Notion-Custom의 컴포넌트를 커스터마이징하고 효과적으로 사용하는 방법을 설명합니다." +--- + +# 커스텀 컴포넌트 사용법 + +React-Notion-Custom은 다양한 Notion 블록 타입에 대한 기본 컴포넌트를 제공합니다. 이 섹션에서는 이러한 기본 컴포넌트를 사용하고 커스터마이징하는 방법, 그리고 새로운 커스텀 컴포넌트를 만드는 방법을 설명합니다. + +## 기본 컴포넌트 사용 예시 + +### Heading 컴포넌트 + +Heading 컴포넌트는 Notion의 제목 블록을 렌더링합니다. 다음은 Heading 컴포넌트를 커스터마이징하는 예시입니다: + +```tsx +import React from "react"; +import { Heading, type HeadingArgs } from "react-notion-custom"; + +const CustomHeading: React.FC<HeadingArgs> = (props) => { + // level 3 헤딩에 밑줄 추가 + if (props.type === "heading_3") { + return <Heading {...props} style={{ textDecoration: "underline" }} />; + } + return <Heading {...props} />; +}; + +export default CustomHeading; +``` + +이 예시에서는 `level` 속성을 확인하여 특정 레벨의 헤딩에 대해 스타일을 변경합니다. + +### Paragraph 컴포넌트 + +Paragraph 컴포넌트는 일반 텍스트 블록을 렌더링합니다. 다음은 Paragraph 컴포넌트를 커스터마이징하는 예시입니다: + +```tsx +import React from "react"; +import { Paragraph, type ParagraphArgs } from "react-notion-custom"; + +const CustomParagraph: React.FC<ParagraphArgs> = (props) => { + return ( + <Paragraph + {...props} + className="custom-paragraph" + style={{ lineHeight: "1.8", marginBottom: "1em" }} + /> + ); +}; + +export default CustomParagraph; +``` + +이 예시에서는 모든 단락에 대해 줄 간격과 하단 여백을 조정하고, 사용자 정의 클래스를 추가합니다. + +## Toggle 컴포넌트 커스터마이징 예시 + +Toggle 컴포넌트는 Notion의 토글 블록을 구현합니다. 다음은 Toggle 컴포넌트를 커스터마이징하는 고급 예시입니다: + +```tsx +import React, { useState } from "react"; +import { Toggle, type ToggleArgs } from "react-notion-custom"; +import { ChevronDown, ChevronRight } from "your-icon-library"; + +const CustomToggle: React.FC<ToggleArgs> = (props) => { + const [isOpen, setIsOpen] = useState(false); + + const handleChangeOpen = (open: boolean) => { + setIsOpen(open); + // 여기에 추가적인 로직을 넣을 수 있습니다. + console.log(`Toggle state changed to: ${open}`); + }; + + return ( + <Toggle {...props} isOpen={isOpen} onChangeOpen={handleChangeOpen}> + <Toggle.Icon> + {isOpen ? <ChevronDown size={20} /> : <ChevronRight size={20} />} + </Toggle.Icon> + <Toggle.Content>{props.children}</Toggle.Content> + </Toggle> + ); +}; + +export default CustomToggle; +``` + +이 예시에서는: + +1. `useState`를 사용하여 토글의 열림/닫힘 상태를 관리합니다. +2. `handleChangeOpen` 함수를 통해 상태 변경을 처리하며, 필요에 따라 추가 로직을 구현할 수 있습니다. +3. `Toggle` 컴포넌트에 `isOpen`과 `onChangeOpen` prop을 전달하여 상태를 직접 제어합니다. +4. `isOpen` 상태에 따라 다른 아이콘을 표시합니다. + +`<Toggle.Icon>`에 컨텐츠를 제공하지 않으면 기본 아이콘이 사용됩니다. + +## 커스텀 컴포넌트 적용하기 + +React-Notion-Custom에서 커스텀 컴포넌트를 사용하는 방법은 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; +import CustomHeading from "./CustomHeading"; +import CustomParagraph from "./CustomParagraph"; +import CustomToggle from "./CustomToggle"; + +const MyNotionPage = ({ pageData }) => { + const customComponents = { + heading_1: CustomHeading, + heading_2: CustomHeading, + heading_3: CustomHeading, + paragraph: CustomParagraph, + toggle: CustomToggle, + }; + + return ( + <Notion custom={customComponents}> + <Notion.Body> + <Notion.Blocks blocks={pageData.blocks} /> + </Notion.Body> + </Notion> + ); +}; +``` + +이 예시에서 `custom` prop을 통해 커스텀 컴포넌트를 Notion 컴포넌트에 전달합니다. 각 블록 타입에 대해 커스텀 컴포넌트를 지정할 수 있습니다. + +## 완전한 커스텀 컴포넌트 만들기 + +React-Notion-Custom의 기본 컴포넌트를 사용하지 않고, 완전히 새로운 컴포넌트를 만들 수도 있습니다. 다음은 Todo 컴포넌트를 처음부터 만드는 예시입니다: + +```tsx +import React from "react"; +import { RichText, type TodoProps } from "react-notion-custom"; + +const Todo: React.FC<TodoProps> = ({ children, ...props }) => { + const { + to_do: { color, rich_text: texts, checked }, + } = props; + + const colorClass = color !== "default" ? `notion-${color}` : ""; + + return ( + <div className={`notion-block notion-to-do ${colorClass}`}> + <div className="notion-to-do-item"> + <div className="notion-to-do-item-content"> + <input + type="checkbox" + checked={checked} + readOnly + className="notion-to-do-checkbox" + /> + <div + className={`notion-to-do-text ${checked ? "notion-to-do-checked" : ""}`} + > + <RichText props={texts} /> + </div> + </div> + {children} + </div> + </div> + ); +}; + +export default Todo; +``` + +이 예시에서 주의할 점: + +- RichText 컴포넌트만 react-notion-custom에서 import합니다. 이는 복잡한 텍스트 렌더링을 처리하기 위함입니다. +- CSS 클래스 이름은 모두 notion-으로 시작합니다. 이는 React-Notion-Custom의 스타일 규칙을 따르는 것입니다. +- gnotion-${color} 형식의 클래스를 추가합니다. 기본 색상("default")의 경우 추가 클래스를 적용하지 않습니다. +- 컴포넌트는 children prop을 받아 하위 컨텐츠를 렌더링할 수 있게 합니다. 이는 중첩된 구조를 지원하기 위함입니다. + +## 컴포넌트 작성 시 주의사항 + +1. **타입 안정성**: TypeScript를 사용하여 prop 타입을 명확히 정의하세요. React-Notion-Custom에서 제공하는 타입(예: `HeadingArgs`, `ParagraphArgs`)을 활용하세요. +2. **prop 전달**: 커스텀 컴포넌트에서 기본 컴포넌트로 모든 prop을 전달하려면 `{...props}`를 사용하세요. 이는 타입 안정성을 유지하면서 불필요한 prop 나열을 방지합니다. +3. **스타일 오버라이딩**: 기존 스타일을 완전히 대체하지 않도록 주의하세요. 대신 `className`을 추가하거나 `style` prop을 확장하는 방식을 사용하세요. +4. **성능 고려**: 불필요한 리렌더링을 방지하기 위해 `React.memo`나 `useMemo`, `useCallback`을 적절히 사용하세요. +5. **접근성**: 커스텀 컴포넌트를 만들 때 접근성(a11y)을 고려하세요. 예를 들어, 토글 버튼에 적절한 `aria-` 속성을 추가하는 것이 좋습니다. +6. **테마 지원**: React-Notion-Custom의 테마 시스템과 호환되도록 커스텀 컴포넌트를 설계하세요. CSS 변수를 활용하면 다크 모드 등의 테마 전환을 쉽게 지원할 수 있습니다. + +## 커스텀 컴포넌트 적용하기 + +React-Notion-Custom에서 커스텀 컴포넌트를 사용하는 방법은 다음과 같습니다: + +```jsx +import { Notion, type NotionPage, type CustomComponents } from 'react-notion-custom'; +import CustomParagraph from './CustomParagraph'; +import CustomToggle from './CustomToggle'; + +const MyNotionPage = ({ pageData }: { pageData: NotionPage }) => { + const customComponents = useMemo<CustomComponents>(() => ({ + paragraph: CustomParagraph, + toggle: CustomToggle, + }), []); + + return ( + <Notion custom={customComponents}> + <Notion.Cover cover={pageData.cover} /> + <Notion.Body> + <Notion.Title title={pageData.title} /> + <Notion.Blocks blocks={pageData.blocks} /> + </Notion.Body> + </Notion> + ); +}; +``` + +이 예시에서 custom prop을 통해 커스텀 컴포넌트를 Notion 컴포넌트에 전달합니다. + +이러한 가이드라인을 따르면 React-Notion-Custom의 기능을 확장하면서도 일관성과 유지보수성을 유지할 수 있습니다. diff --git a/packages/docs/content/guide/kr/02. customization-guide/03. custom-style.md b/packages/docs/content/guide/kr/02. customization-guide/03. custom-style.md new file mode 100644 index 0000000..0e0abd0 --- /dev/null +++ b/packages/docs/content/guide/kr/02. customization-guide/03. custom-style.md @@ -0,0 +1,168 @@ +--- +group: "customization-guide" +order: 3 +title: "CSS 구조 및 스타일링 가이드" +slug: "css-structure-and-styling" +description: "React-Notion-Custom의 CSS 구조를 이해하고 효과적인 스타일링 방법을 학습합니다." +--- + +# CSS 구조 및 스타일링 가이드 + +React-Notion-Custom은 유연하고 확장 가능한 CSS 구조를 제공합니다. 이 섹션에서는 CSS 변수 시스템, 주요 스타일링 포인트, 그리고 Indent 적용 원리에 대해 설명합니다. + +## CSS 변수 시스템 + +React-Notion-Custom은 CSS 변수를 사용하여 전역 스타일을 정의합니다. 이를 통해 테마 변경이나 전체적인 스타일 조정을 쉽게 할 수 있습니다. + +주요 CSS 변수들은 다음과 같습니다: + +```css +.notion { + --notion-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, + "Segoe UI Emoji", "Segoe UI Symbol"; + --notion-max-width: 720px; + --notion-header-height: 45px; + --notion-indent: 27px; + + /* 색상 변수 */ + --fg-color: rgb(55, 53, 47); + --fg-color-0: rgba(55, 53, 47, 0.09); + --fg-color-1: rgba(55, 53, 47, 0.16); + --fg-color-2: rgba(55, 53, 47, 0.4); + --fg-color-3: rgba(55, 53, 47, 0.6); + --fg-color-4: #000; + --fg-color-5: rgb(233, 233, 231); + --fg-color-6: rgba(55, 53, 47, 0.8); + --fg-color-icon: var(--fg-color); + + --bg-color: #fff; + --bg-color-0: rgba(135, 131, 120, 0.15); + --bg-color-1: rgb(247, 246, 243); + --bg-color-2: rgba(135, 131, 120, 0.15); + + --select-color-0: rgb(46, 170, 220); + --select-color-1: rgba(35, 131, 226, 0.28); + --select-color-2: #d9eff8; +} +``` + +이러한 변수들을 재정의하여 전체적인 스타일을 쉽게 변경할 수 있습니다. + +## 주요 스타일링 포인트 + +1. **클래스 네이밍 규칙**: 모든 클래스는 `notion-`으로 시작합니다. 이는 스타일 충돌을 방지합니다. + + 예: `.notion-block`, `.notion-h1`, `.notion-toggle` + +2. **블록 레벨 스타일**: 모든 블록 레벨 요소에는 `notion-block` 클래스가 적용됩니다. + + ```css + .notion-block { + display: block; + } + ``` + +3. **색상 적용**: 색상은 CSS 변수를 통해 적용됩니다. + + ```css + .notion-text { + color: var(--fg-color); + } + ``` + +4. **반응형 디자인**: `--notion-max-width` 변수를 활용하여 반응형 레이아웃을 구현합니다. + + ```css + .notion-body { + width: 100%; + max-width: var(--notion-max-width); + margin: 0 auto; + } + ``` + +## Indent 적용 원리 + +React-Notion-Custom은 재귀적인 구조를 통해 들여쓰기를 구현합니다. 이는 CSS에서 다음과 같이 처리됩니다: + +```css +.notion-block > .notion-block { + margin-left: var(--notion-indent); +} + +.notion-block > .notion-display-contents > .notion-block { + margin-left: var(--notion-indent); +} +``` + +이 CSS 규칙은 중첩된 블록에 대해 자동으로 들여쓰기를 적용합니다. `--notion-indent` 변수를 조정하여 들여쓰기 정도를 쉽게 변경할 수 있습니다. + +## 다크 모드 및 커스텀 테마 + +React-Notion-Custom은 기본적으로 다크 모드를 지원합니다. 다크 모드는 다음과 같이 구현되어 있습니다: + +```css +[data-theme="dark"] .notion { + --fg-color: rgba(255, 255, 255, 0.9); + --bg-color: #2f3437; + /* 기타 다크 모드 관련 변수들... */ +} +``` + +또한, 커스텀 테마를 쉽게 적용할 수 있습니다. `data-theme` 속성을 사용하여 원하는 테마를 적용할 수 있습니다: + +```jsx +<Notion data-theme="custom">{/* Notion 컨텐츠 */}</Notion> +``` + +그리고 CSS에서 다음과 같이 스타일을 정의할 수 있습니다: + +```css +.notion[data-theme="custom"] { + --fg-color: #333; + --bg-color: #f4f4f4; + /* 기타 커스텀 테마 관련 변수들... */ +} +``` + +이 방식을 사용하면 선택자 우선순위를 활용하여 기본 스타일을 쉽게 오버라이딩할 수 있습니다. + +## 스타일 커스터마이징 예시 + +1. **글로벌 폰트 변경**: + + ```css + .notion[data-theme="custom"] { + --notion-font: "Roboto", sans-serif; + } + ``` + +2. **헤딩 스타일 변경**: + + ```css + .notion[data-theme="custom"] .notion-h1 { + font-size: 2.5em; + color: var(--select-color-0); + border-bottom: 2px solid var(--fg-color-1); + } + ``` + +3. **들여쓰기 조정**: + + ```css + .notion[data-theme="custom"] { + --notion-indent: 20px; + } + ``` + +4. **다크 모드 구현**: + + ```css + [data-theme="dark"] .notion[data-theme="custom"] { + --fg-color: rgba(255, 255, 255, 0.9); + --bg-color: #2f3437; + /* 다른 색상 변수들도 적절히 조정 */ + } + ``` + +이러한 CSS 구조와 스타일링 가이드를 따르면, React-Notion-Custom을 사용하여 일관성 있고 유지보수가 쉬운 스타일을 구현할 수 있습니다. 또한, 필요에 따라 세부적인 커스터마이징도 가능합니다. diff --git a/packages/docs/content/guide/kr/03. block-types/01. block-type-guide-intro.md b/packages/docs/content/guide/kr/03. block-types/01. block-type-guide-intro.md new file mode 100644 index 0000000..5146a53 --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/01. block-type-guide-intro.md @@ -0,0 +1,242 @@ +--- +group: "block-types" +order: 1 +title: "블록 타입 가이드 소개" +slug: "block-type-guide-intro" +description: "React-Notion-Custom에서 지원하는 블록 타입들의 개요, 사용 방법, 커스터마이징 옵션, 그리고 내부 동작 원리를 소개합니다." +--- + +# 블록 타입 가이드 소개 + +React-Notion-Custom은 Notion의 다양한 블록 타입을 지원하며, 각 블록 타입에 대해 Notion과 최대한 유사한 스타일의 컴포넌트를 제공합니다. 이 가이드에서는 현재 지원되는 블록 타입들, 각 블록 타입의 Props, 커스터마이징 방법, 그리고 내부 동작 원리에 대해 설명합니다. + +## 지원되는 블록 타입 + +React-Notion-Custom에서 현재 지원되는 블록 타입과 지원 예정인 블록 타입들의 목록입니다: + +| Block Type | 지원 여부 | Block Type Enum | +| ------------------------ | --------- | ---------------------- | +| Paragraph | ✅ Yes | `paragraph` | +| Heading 1 | ✅ Yes | `heading_1` | +| Heading 2 | ✅ Yes | `heading_2` | +| Heading 3 | ✅ Yes | `heading_3` | +| Bulleted List Item | ✅ Yes | `bulleted_list_item` | +| Numbered List Item | ✅ Yes | `numbered_list_item` | +| To-do | ❌ No | `to_do` | +| Toggle | ✅ Yes | `toggle` | +| Quote | ✅ Yes | `quote` | +| Callout | ✅ Yes | `callout` | +| Equation | ❌ No | `equation` | +| Code | ❌ No | `code` | +| Image | ❌ No | `image` | +| Video | ❌ No | `video` | +| Bookmark | ❌ No | `bookmark` | +| Divider | ✅ Yes | `divider` | +| Table | ❌ No | `table` | +| Table Row | ❌ No | `table_row` | +| Column | ❌ No | `column` | +| Column List | ❌ No | `column_list` | +| Audio | ❌ No | `audio` | +| Synced Block | ❌ No | `synced_block` | +| Table Of Contents | ❌ No | `table_of_contents` | +| Embed | ❌ No | `embed` | +| Figma | ❌ No | `figma` | +| Google Maps | ❌ No | `maps` | +| Google Drive | ❌ No | `drive` | +| Tweet | ❌ No | `tweet` | +| PDF | ❌ No | `pdf` | +| File | ❌ No | `file` | +| Link | ❌ No | `text` (inline) | +| Page Link | ❌ No | `page` | +| External Page Link | ❌ No | `text` (inline) | +| Collections | ❌ No | - | +| Collection View | ❌ No | `collection_view` | +| Collection View Table | ❌ No | `collection_view` | +| Collection View Gallery | ❌ No | `collection_view` | +| Collection View Board | ❌ No | `collection_view` | +| Collection View List | ❌ No | `collection_view` | +| Collection View Calendar | ❌ No | `collection_view` | +| Collection View Page | ❌ No | `collection_view_page` | + +이 목록은 지속적으로 업데이트될 예정이며, 향후 더 많은 블록 타입을 지원할 계획입니다. + +## Props 사용법 + +React-Notion-Custom은 각 블록 타입에 대한 Props 타입을 제공합니다. 이러한 Props 타입들은 라이브러리에서 직접 import하여 사용할 수 있습니다. + +예를 들어, Paragraph 컴포넌트의 Props는 다음과 같이 import하고 사용할 수 있습니다: + +```typescript +import { ParagraphProps } from "react-notion-custom"; + +// ParagraphProps의 구조 +interface ParagraphProps { + type: "paragraph"; + paragraph: { + rich_text: Array<RichTextItemResponse>; + color: string; + }; + id: string; + has_children?: boolean; +} + +// 사용 예시 +const MyParagraph: React.FC<ParagraphProps> = (props) => { + // 커스텀 구현 +}; +``` + +각 블록 타입별 Props의 상세한 구조는 해당 블록 타입 문서에서 확인할 수 있습니다. + +## 커스텀 컴포넌트 적용 + +React-Notion-Custom의 큰 장점 중 하나는 각 블록 타입에 대해 커스텀 컴포넌트로 완전히 교체할 수 있다는 점입니다. 커스텀 컴포넌트를 적용하는 방법은 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; +import CustomParagraph from "./CustomParagraph"; +import CustomHeading from "./CustomHeading"; + +const customComponents = { + paragraph: CustomParagraph, + heading_1: CustomHeading, + heading_2: CustomHeading, + heading_3: CustomHeading, + // ... 기타 블록 타입에 대한 커스텀 컴포넌트 +}; + +function MyNotionPage({ blocks }) { + return ( + <Notion custom={customComponents}> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +`Notion` 컴포넌트에 주입되는 `components`의 타입은 다음과 같습니다: + +```typescript +type NotionComponents = Record<string, React.ComponentType<any>>; +``` + +여기서 `key`는 Notion 블록의 타입(예: 'paragraph', 'heading_1' 등)이고, `value`는 해당 타입을 렌더링할 React 컴포넌트입니다. + +## 데이터 전처리 과정 + +React-Notion-Custom은 Notion API에서 가져온 블록 데이터를 UI 렌더링에 최적화된 형태로 전처리합니다. 이 과정에서 `ContextedBlock`이라는 새로운 타입을 정의하여 사용합니다. + +``` ++----------------------+ +| Notion API | +| Block Data | +| +------------------+ | +| | Block | | +| | - id | | +| | - type | | +| | - has_children | | +| | - [type_specific]| | +| +------------------+ | ++----------------------+ + | + | (Input) + v ++---------------------------+ +| resolveToContextedBlocks | +| +-------------------------+ +| | For each block: | +| | +---------------------+ | +| | |resolveToContextedBlo| | +| | |ck (recursive) | | +| | +---------------------+ | +| | | | +| | v | +| | Map parent-child | +| | relationships | +| +-------------------------+ +| | +| v +| Map sibling relationships | ++---------------------------+ + | + | (Output) + v ++---------------------------+ +| ContextedBlocks | +| +-------------------------+ +| | ContextedBlock | +| | - ...Block properties | +| | - context: | +| | - previous (sibling) | +| | - next (sibling) | +| | - parent | +| | - blocks (children) | +| +-------------------------+ ++---------------------------+ + | + | (Used by) + v + +----------------+ + | Notion.Blocks | + | Component | + +----------------+ +``` + +`ContextedBlock`은 기존 `Block` 타입을 확장하여 다음과 같은 추가 정보를 포함합니다: + +- 이전 블록 (형제 관계) +- 다음 블록 (형제 관계) +- 부모 블록 + +이러한 추가 정보는 특정 블록 컴포넌트에서 유용하게 사용될 수 있습니다. + +## 렌더링 프로세스 + +React-Notion-Custom의 렌더링 프로세스는 다음과 같습니다: + +``` ++-------------------+ +------------------+ +| Custom | | Default | +| Components | | Components | ++-------------------+ +------------------+ + | | + | +-----------------+ | + +-->| Notion |<--+ + | Component | + |(React.Provider) | + +-----------------+ + | | + +----------+ +------------+ + | | ++----------------+ +----------------+ +| Notion.Cover | | Notion.Body | ++----------------+ +----------------+ + | + +----------------+ + | Notion.Title | + +----------------+ + | + +----------------+ + | Notion.Blocks | + +----------------+ + | + v + +----------------+ + | Rendered | + | Notion Page | + +----------------+ +``` + +이 프로세스를 통해 커스텀 컴포넌트와 기본 컴포넌트가 함께 작동하여 Notion 페이지를 렌더링합니다. + +## 스타일링 + +현재 제공되는 Notion 컴포넌트들은 Notion의 스타일을 최대한 유사하게 구현했습니다. 각 컴포넌트는 `notion-` 접두사를 가진 CSS 클래스를 사용하여 스타일링되어 있습니다. + +## 향후 계획 + +- 더 많은 블록 타입 지원 추가 +- 테마를 적용한 컴포넌트 셋 개발 +- 고급 커스터마이징 옵션 확장 + +이어지는 페이지들에서 각 블록 타입에 대한 상세한 설명, Props 구조, 사용 예시, 그리고 커스터마이징 옵션을 확인할 수 있습니다. diff --git a/packages/docs/content/guide/kr/03. block-types/02. heading.md b/packages/docs/content/guide/kr/03. block-types/02. heading.md new file mode 100644 index 0000000..043bbc8 --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/02. heading.md @@ -0,0 +1,124 @@ +--- +group: "block-types" +order: 3 +title: "Heading 블록" +slug: "notion-block-heading" +description: "React-Notion-Custom의 Heading 블록 타입에 대한 상세 설명입니다." +--- + +# Heading 블록 + +Heading 블록은 문서의 구조를 나타내는 데 사용되며, 세 가지 레벨(Heading 1, Heading 2, Heading 3)을 지원합니다. + +## 데이터 구조 + +Heading 블록의 Notion API 데이터 구조는 다음과 같습니다 (Heading 1의 예시): + +```json +{ + "type": "heading_1", + "heading_1": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a heading", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a heading", + "href": null + } + ], + "color": "default", + "is_toggleable": false + } +} +``` + +- `type`: "heading_1", "heading_2", 또는 "heading_3" 중 하나입니다. +- `rich_text`: 헤딩 텍스트의 내용과 스타일 정보를 담고 있는 배열입니다. +- `color`: 헤딩의 색상을 지정합니다. +- `is_toggleable`: 토글 기능 사용 여부를 나타냅니다. + +## React 컴포넌트 + +React-Notion-Custom에서 Heading 블록을 렌더링하는 컴포넌트는 다음과 같습니다: + +```jsx +import React, { useMemo } from "react"; +import type { HeadingsProps, HeadingConfig } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +const Headings: React.FC<HeadingsProps> = ({ children, type, ...props }) => { + const { + [type]: { color, rich_text: texts, is_toggleable }, + } = props; + + const { headingTag: HeadingTag, headingClassName } = + useMemo<HeadingConfig>(() => { + switch (type) { + case "heading_2": + return { headingTag: "h2", headingClassName: "notion-h2" }; + case "heading_3": + return { headingTag: "h3", headingClassName: "notion-h3" }; + default: + return { headingTag: "h1", headingClassName: "notion-h1" }; + } + }, [type]); + + return ( + <div + className={`notion-block ${headingClassName} ${getColorCss(color)}`} + > + <HeadingTag className={`notion-h-content ${headingClassName}-content`}> + <RichText props={texts} /> + </HeadingTag> + {children} + </div> + ); +}; + +export default Headings; +``` + +## 사용 예시 + +Heading 블록을 사용하는 예시는 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +여기서 `blocks`는 Notion API로부터 받아온 블록 데이터 배열입니다. + +## 스타일링 + +Heading 블록의 스타일은 다음 CSS 클래스를 통해 커스터마이즈할 수 있습니다: + +- `.notion-block`: 모든 Notion 블록에 적용되는 기본 스타일 +- `.notion-h1`, `.notion-h2`, `.notion-h3`: 각 헤딩 레벨에 대한 특정 스타일 +- `.notion-h1-content`, `.notion-h2-content`, `.notion-h3-content`: 각 헤딩 내용의 스타일 + +추가적인 스타일링이 필요한 경우, 이 클래스들을 대상으로 CSS를 작성하면 됩니다. + +## 주의사항 + +- Heading 블록은 문서의 구조를 나타내는 중요한 요소이므로, 적절한 레벨의 헤딩을 사용하는 것이 좋습니다. +- `is_toggleable` 속성이 true인 경우, 해당 헤딩은 토글 기능을 가지게 됩니다. 이 경우 추가적인 로직이 필요할 수 있습니다. diff --git a/packages/docs/content/guide/kr/03. block-types/03. bulleted-list-item.md b/packages/docs/content/guide/kr/03. block-types/03. bulleted-list-item.md new file mode 100644 index 0000000..628cd0c --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/03. bulleted-list-item.md @@ -0,0 +1,134 @@ +--- +group: "block-types" +order: 4 +title: "Bulleted List Item 블록" +slug: "notion-block-bulleted-list-item" +description: "React-Notion-Custom의 Bulleted List Item 블록 타입에 대한 상세 설명입니다." +--- + +# Bulleted List Item 블록 + +Bulleted List Item 블록은 순서가 없는 목록을 만드는 데 사용됩니다. 각 항목은 글머리 기호(bullet)로 시작합니다. + +## 데이터 구조 + +Bulleted List Item 블록의 Notion API 데이터 구조는 다음과 같습니다: + +```json +{ + "type": "bulleted_list_item", + "bulleted_list_item": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a bulleted list item", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a bulleted list item", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: 리스트 항목의 텍스트 내용과 스타일 정보를 담고 있는 배열입니다. +- `color`: 텍스트의 색상을 지정합니다. + +## React 컴포넌트 + +React-Notion-Custom에서 Bulleted List Item 블록을 렌더링하는 컴포넌트는 다음과 같습니다: + +```jsx +import React from "react"; +import type { BulletedListItemArgs } from "../types"; +import { bulletedListItemMarker, getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type BulletedListItemProps = { + children?: React.ReactNode; +} & BulletedListItemArgs; + +const BulletedListItem: React.FC<BulletedListItemProps> = ({ + children, + ...props +}) => { + const { + bulleted_list_item: { rich_text: texts, color }, + } = props; + const { marker, format } = bulletedListItemMarker.getMarker(props); + + return ( + <ul + data-notion-marker-format={format} + className={`notion-block notion-list-bulleted ${getColorCss(color)}`} + > + <li className="notion-display-contents"> + <div className="notion-list-bulleted-content"> + <span + data-notion-marker-format={format} + className="notion-list-marker" + > + {marker} + </span> + <p> + <RichText props={texts} /> + </p> + </div> + {children} + </li> + </ul> + ); +}; + +export default BulletedListItem; +``` + +## 사용 예시 + +Bulleted List Item 블록을 사용하는 예시는 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +여기서 `blocks`는 Notion API로부터 받아온 블록 데이터 배열입니다. + +## 스타일링 + +Bulleted List Item 블록의 스타일은 다음 CSS 클래스를 통해 커스터마이즈할 수 있습니다: + +- `.notion-block`: 모든 Notion 블록에 적용되는 기본 스타일 +- `.notion-list-bulleted`: Bulleted List Item 블록 특정 스타일 +- `.notion-list-bulleted-content`: 리스트 항목 내용의 스타일 +- `.notion-list-marker`: 글머리 기호의 스타일 + +추가적인 스타일링이 필요한 경우, 이 클래스들을 대상으로 CSS를 작성하면 됩니다. + +## 중첩된 리스트 처리 + +Bulleted List Item은 중첩될 수 있습니다. 중첩된 리스트는 `children` prop을 통해 처리됩니다. 중첩 레벨에 따라 글머리 기호의 모양이 달라질 수 있으며, 이는 `bulletedListItemMarker.getMarker` 함수에서 처리됩니다. + +## 주의사항 + +- Bulleted List Item 블록은 연속적으로 사용될 때 자동으로 하나의 리스트로 그룹화됩니다. +- 중첩된 리스트를 사용할 때는 적절한 들여쓰기를 통해 계층 구조를 명확히 표현하는 것이 좋습니다. +- 글머리 기호의 모양은 Notion의 기본 스타일을 따르지만, CSS를 통해 커스터마이즈할 수 있습니다. diff --git a/packages/docs/content/guide/kr/03. block-types/05. numbered-list-item.md b/packages/docs/content/guide/kr/03. block-types/05. numbered-list-item.md new file mode 100644 index 0000000..71c2afa --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/05. numbered-list-item.md @@ -0,0 +1,145 @@ +--- +group: "block-types" +order: 5 +title: "Numbered List Item 블록" +slug: "numbered-list-item" +description: "React-Notion-Custom의 Numbered List Item 블록 타입에 대한 상세 설명입니다." +--- + +# Numbered List Item 블록 + +Numbered List Item 블록은 순서가 있는 목록을 만드는 데 사용됩니다. 각 항목은 순차적인 번호로 시작합니다. + +## 데이터 구조 + +Numbered List Item 블록의 Notion API 데이터 구조는 다음과 같습니다: + +```json +{ + "type": "numbered_list_item", + "numbered_list_item": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a numbered list item", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a numbered list item", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: 리스트 항목의 텍스트 내용과 스타일 정보를 담고 있는 배열입니다. +- `color`: 텍스트의 색상을 지정합니다. + +## React 컴포넌트 + +React-Notion-Custom에서 Numbered List Item 블록을 렌더링하는 컴포넌트는 다음과 같습니다: + +```jsx +import React from "react"; +import type { NumberedListItemArgs } from "../types"; +import { getColorCss, numberedListItemMarker } from "../utils"; +import RichText from "./internal/rich-text"; + +type NumberedListProps = { + children?: React.ReactNode; +} & NumberedListItemArgs; + +const NumberedListItem: React.FC<NumberedListProps> = ({ + children, + ...props +}) => { + const { + numbered_list_item: { rich_text: texts, color }, + } = props; + const { marker, format } = numberedListItemMarker.getMarker(props); + + return ( + <ol + data-notion-marker-format={format} + className={`notion-block notion-list-numbered ${getColorCss(color)}`} + > + <li className="notion-display-contents"> + <div className="notion-list-numbered-content"> + <span + data-notion-marker-format={format} + className="notion-list-marker" + > + {marker} + </span> + <p> + <RichText props={texts} /> + </p> + </div> + {children} + </li> + </ol> + ); +}; + +export default NumberedListItem; +``` + +## 사용 예시 + +Numbered List Item 블록을 사용하는 예시는 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +여기서 `blocks`는 Notion API로부터 받아온 블록 데이터 배열입니다. + +## 스타일링 + +Numbered List Item 블록의 스타일은 다음 CSS 클래스를 통해 커스터마이즈할 수 있습니다: + +- `.notion-block`: 모든 Notion 블록에 적용되는 기본 스타일 +- `.notion-list-numbered`: Numbered List Item 블록 특정 스타일 +- `.notion-list-numbered-content`: 리스트 항목 내용의 스타일 +- `.notion-list-marker`: 번호의 스타일 + +추가적인 스타일링이 필요한 경우, 이 클래스들을 대상으로 CSS를 작성하면 됩니다. + +## 번호 매기기 방식 + +Numbered List Item의 번호 매기기 방식은 `numberedListItemMarker.getMarker` 함수에 의해 결정됩니다. 이 함수는 현재 항목의 위치와 중첩 레벨을 고려하여 적절한 번호나 문자를 반환합니다. 기본적으로 다음과 같은 순서를 따릅니다: + +1. 최상위 레벨: 1, 2, 3, ... +2. 두 번째 레벨: a, b, c, ... +3. 세 번째 레벨: i, ii, iii, ... + +이 순서는 필요에 따라 커스터마이즈할 수 있습니다. + +## 중첩된 리스트 처리 + +Numbered List Item도 중첩될 수 있습니다. 중첩된 리스트는 `children` prop을 통해 처리됩니다. 중첩 레벨에 따라 번호 매기기 방식이 달라질 수 있으며, 이는 `numberedListItemMarker.getMarker` 함수에서 처리됩니다. + +## 주의사항 + +- Numbered List Item 블록은 연속적으로 사용될 때 자동으로 하나의 리스트로 그룹화됩니다. +- 중첩된 리스트를 사용할 때는 적절한 들여쓰기를 통해 계층 구조를 명확히 표현하는 것이 좋습니다. +- 번호 매기기 방식은 Notion의 기본 스타일을 따르지만, CSS를 통해 커스터마이즈할 수 있습니다. +- 리스트가 중단되었다가 다시 시작될 경우, 번호 매기기가 새로 시작될 수 있으므로 주의가 필요합니다. diff --git a/packages/docs/content/guide/kr/03. block-types/06. Quote.md b/packages/docs/content/guide/kr/03. block-types/06. Quote.md new file mode 100644 index 0000000..2c4d5b9 --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/06. Quote.md @@ -0,0 +1,136 @@ +--- +group: "block-types" +order: 6 +title: "Quote 블록" +slug: "quote" +description: "React-Notion-Custom의 Quote 블록 타입에 대한 상세 설명입니다." +--- + +# Quote 블록 + +Quote 블록은 다른 출처에서 인용한 텍스트를 표시하는 데 사용됩니다. 일반적으로 시각적으로 구분되는 스타일로 표현됩니다. + +## 데이터 구조 + +Quote 블록의 Notion API 데이터 구조는 다음과 같습니다: + +```json +{ + "type": "quote", + "quote": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a quote", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a quote", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: 인용문의 텍스트 내용과 스타일 정보를 담고 있는 배열입니다. +- `color`: 인용문의 색상을 지정합니다. + +## React 컴포넌트 + +React-Notion-Custom에서 Quote 블록을 렌더링하는 컴포넌트는 다음과 같습니다: + +```jsx +import React from "react"; +import type { QuoteArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type QuoteProps = { + children?: React.ReactNode; +} & QuoteArgs; + +const Quote: React.FC<QuoteProps> = ({ children, ...props }) => { + const { + quote: { color, rich_text: texts }, + } = props; + + return ( + <div className={`notion-block notion-quote ${getColorCss(color)}`}> + <div className="notion-quote-content"> + <p> + <RichText props={texts} /> + </p> + {children} + </div> + </div> + ); +}; + +export default Quote; +``` + +## 사용 예시 + +Quote 블록을 사용하는 예시는 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +여기서 `blocks`는 Notion API로부터 받아온 블록 데이터 배열입니다. + +## 스타일링 + +Quote 블록의 스타일은 다음 CSS 클래스를 통해 커스터마이즈할 수 있습니다: + +- `.notion-block`: 모든 Notion 블록에 적용되는 기본 스타일 +- `.notion-quote`: Quote 블록 특정 스타일 +- `.notion-quote-content`: 인용문 내용의 스타일 + +추가적인 스타일링이 필요한 경우, 이 클래스들을 대상으로 CSS를 작성하면 됩니다. 일반적으로 Quote 블록은 다음과 같은 스타일 특성을 가집니다: + +- 왼쪽 또는 양쪽에 두꺼운 테두리 +- 약간의 들여쓰기 +- 배경색 변경 +- 폰트 스타일 변경 (예: 기울임꼴) + +예를 들어, 다음과 같은 CSS를 적용할 수 있습니다: + +```css +.notion-quote { + border-left: 4px solid #ccc; + padding-left: 16px; + margin-left: 0; + margin-right: 0; + font-style: italic; + background-color: #f9f9f9; +} +``` + +## 중첩 지원 + +Quote 블록은 다른 블록을 포함할 수 있습니다. 이는 `children` prop을 통해 처리됩니다. 예를 들어, 인용문 안에 리스트나 다른 텍스트 블록을 포함할 수 있습니다. + +## 주의사항 + +- Quote 블록은 일반적으로 짧은 인용문에 사용됩니다. 긴 인용문의 경우, 가독성을 위해 여러 개의 Quote 블록으로 나누는 것이 좋을 수 있습니다. +- 인용문의 출처를 명시하는 것이 좋습니다. 이는 Quote 블록 아래에 별도의 Paragraph 블록으로 추가할 수 있습니다. +- 접근성을 고려하여, 스크린 리더 사용자를 위해 적절한 ARIA 속성을 추가하는 것이 좋습니다. 예를 들어, `role="blockquote"` 속성을 사용할 수 있습니다. diff --git a/packages/docs/content/guide/kr/03. block-types/07. Paragraph.md b/packages/docs/content/guide/kr/03. block-types/07. Paragraph.md new file mode 100644 index 0000000..be54ac6 --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/07. Paragraph.md @@ -0,0 +1,106 @@ +--- +group: "block-types" +order: 2 +title: "Paragraph 블록" +slug: "paragraph" +description: "React-Notion-Custom의 Paragraph 블록 타입에 대한 상세 설명입니다." +--- + +# Paragraph 블록 + +Paragraph 블록은 일반 텍스트를 표현하는 가장 기본적인 블록 타입입니다. + +## 데이터 구조 + +Paragraph 블록의 Notion API 데이터 구조는 다음과 같습니다: + +```json +{ + "type": "paragraph", + "paragraph": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a paragraph.", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a paragraph.", + "href": null + } + ], + "color": "default" + } +} +``` + +- `rich_text`: 텍스트의 내용과 스타일 정보를 담고 있는 배열입니다. +- `color`: 텍스트의 색상을 지정합니다. + +## React 컴포넌트 + +React-Notion-Custom에서 Paragraph 블록을 렌더링하는 컴포넌트는 다음과 같습니다: + +```jsx +import React from "react"; +import type { ParagraphArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type ParagraphProps = { + children?: React.ReactNode; +} & ParagraphArgs; + +const Paragraph: React.FC<ParagraphProps> = ({ children, ...props }) => { + const { + paragraph: { color, rich_text: texts }, + } = props; + + return ( + <div className={`notion-block notion-paragraph ${getColorCss(color)}`}> + <p className="notion-paragraph-content"> + <RichText props={texts} /> + </p> + {children} + </div> + ); +}; + +export default Paragraph; +``` + +## 사용 예시 + +Paragraph 블록을 사용하는 예시는 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +여기서 `blocks`는 Notion API로부터 받아온 블록 데이터 배열입니다. + +## 스타일링 + +Paragraph 블록의 스타일은 다음 CSS 클래스를 통해 커스터마이즈할 수 있습니다: + +- `.notion-block`: 모든 Notion 블록에 적용되는 기본 스타일 +- `.notion-paragraph`: Paragraph 블록 특정 스타일 +- `.notion-paragraph-content`: Paragraph 내용의 스타일 + +추가적인 스타일링이 필요한 경우, 이 클래스들을 대상으로 CSS를 작성하면 됩니다. diff --git a/packages/docs/content/guide/kr/03. block-types/08. Callout.md b/packages/docs/content/guide/kr/03. block-types/08. Callout.md new file mode 100644 index 0000000..349aa27 --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/08. Callout.md @@ -0,0 +1,155 @@ +--- +group: "block-types" +order: 7 +title: "Callout 블록" +slug: "callout" +description: "React-Notion-Custom의 Callout 블록 타입에 대한 상세 설명입니다." +--- + +# Callout 블록 + +Callout 블록은 주목을 끌어야 하는 내용을 강조하는 데 사용됩니다. 주로 아이콘과 함께 색상이 있는 배경으로 표시되어 시각적으로 눈에 띄게 만듭니다. + +## 데이터 구조 + +Callout 블록의 Notion API 데이터 구조는 다음과 같습니다: + +```json +{ + "type": "callout", + "callout": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "This is a callout", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a callout", + "href": null + } + ], + "icon": { + "type": "emoji", + "emoji": "💡" + }, + "color": "gray_background" + } +} +``` + +- `rich_text`: Callout의 텍스트 내용과 스타일 정보를 담고 있는 배열입니다. +- `icon`: Callout과 함께 표시될 아이콘 정보입니다. 이모지나 외부 이미지 URL이 될 수 있습니다. +- `color`: Callout의 배경색을 지정합니다. + +## React 컴포넌트 + +React-Notion-Custom에서 Callout 블록을 렌더링하는 컴포넌트는 다음과 같습니다: + +```jsx +import React from "react"; +import type { CalloutArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; +import Icon from "./internal/icon"; + +type CalloutProps = { + children?: React.ReactNode; +} & CalloutArgs; + +const Callout: React.FC<CalloutProps> = ({ children, ...props }) => { + const { callout } = props; + + return ( + <div + className={`notion-block notion-callout ${getColorCss(callout.color)}`} + > + <div className="notion-callout-content"> + <div className="notion-callout-icon" aria-hidden="true"> + <Icon icon={callout.icon} /> + </div> + <div className="notion-callout-text"> + <RichText props={callout.rich_text} /> + </div> + </div> + {children} + </div> + ); +}; + +export default Callout; +``` + +## 사용 예시 + +Callout 블록을 사용하는 예시는 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +여기서 `blocks`는 Notion API로부터 받아온 블록 데이터 배열입니다. + +## 아이콘 처리 + +Callout 블록의 아이콘은 `Icon` 컴포넌트를 통해 처리됩니다. 이 컴포넌트는 이모지와 외부 이미지 URL을 모두 지원합니다. 아이콘 타입에 따라 적절한 렌더링 방식을 선택합니다. + +## 스타일링 + +Callout 블록의 스타일은 다음 CSS 클래스를 통해 커스터마이즈할 수 있습니다: + +- `.notion-block`: 모든 Notion 블록에 적용되는 기본 스타일 +- `.notion-callout`: Callout 블록 특정 스타일 +- `.notion-callout-content`: Callout 내용의 스타일 +- `.notion-callout-icon`: Callout 아이콘의 스타일 +- `.notion-callout-text`: Callout 텍스트의 스타일 + +추가적인 스타일링이 필요한 경우, 이 클래스들을 대상으로 CSS를 작성하면 됩니다. 예를 들어: + +```css +.notion-callout { + border-radius: 4px; + padding: 16px; + display: flex; + align-items: center; +} + +.notion-callout-icon { + margin-right: 12px; + font-size: 24px; +} + +.notion-callout-text { + flex: 1; +} +``` + +## 색상 처리 + +Callout의 `color` 속성은 배경색을 결정합니다. `getColorCss` 유틸리티 함수를 사용하여 적절한 CSS 클래스를 생성합니다. 이 함수는 Notion의 색상 이름을 CSS 클래스로 변환합니다. + +## 중첩 지원 + +Callout 블록은 다른 블록을 포함할 수 있습니다. 이는 `children` prop을 통해 처리됩니다. 예를 들어, Callout 안에 리스트나 다른 텍스트 블록을 포함할 수 있습니다. + +## 주의사항 + +- Callout 블록은 주요 정보나 경고를 강조하는 데 효과적입니다. 그러나 과도한 사용은 오히려 주의를 분산시킬 수 있으므로 적절히 사용해야 합니다. +- 아이콘과 배경색의 조합이 접근성 기준을 충족하는지 확인해야 합니다. 특히 텍스트와 배경 간의 충분한 대비를 유지해야 합니다. +- 스크린 리더 사용자를 위해 아이콘에 적절한 대체 텍스트를 제공하는 것이 좋습니다. diff --git a/packages/docs/content/guide/kr/03. block-types/09. Toggle.md b/packages/docs/content/guide/kr/03. block-types/09. Toggle.md new file mode 100644 index 0000000..95feef5 --- /dev/null +++ b/packages/docs/content/guide/kr/03. block-types/09. Toggle.md @@ -0,0 +1,179 @@ +--- +group: "block-types" +order: 8 +title: "Toggle 블록" +slug: "toggle" +description: "React-Notion-Custom의 Toggle 블록 타입에 대한 상세 설명입니다." +--- + +# Toggle 블록 + +Toggle 블록은 접을 수 있는 콘텐츠를 생성하는 데 사용됩니다. 사용자가 토글을 클릭하면 숨겨진 내용이 펼쳐지거나 접히는 인터랙티브한 요소입니다. + +## 데이터 구조 + +Toggle 블록의 Notion API 데이터 구조는 다음과 같습니다: + +```json +{ + "type": "toggle", + "toggle": { + "rich_text": [ + { + "type": "text", + "text": { + "content": "Click to toggle", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Click to toggle", + "href": null + } + ], + "color": "default", + "children": [ + // 중첩된 블록들... + ] + } +} +``` + +- `rich_text`: 토글의 표시 텍스트와 스타일 정보를 담고 있는 배열입니다. +- `color`: 토글 텍스트의 색상을 지정합니다. +- `children`: 토글을 펼쳤을 때 표시될 중첩된 블록들의 배열입니다. + +## React 컴포넌트 + +React-Notion-Custom에서 Toggle 블록을 렌더링하는 컴포넌트는 다음과 같습니다: + +```jsx +import React, { useState, useCallback } from "react"; +import type { ToggleArgs } from "../types"; +import { getColorCss } from "../utils"; +import RichText from "./internal/rich-text"; + +type ToggleProps = { + children?: React.ReactNode; +} & ToggleArgs; + +const Toggle: React.FC<ToggleProps> = ({ children, ...props }) => { + const { + toggle: { color, rich_text: texts }, + } = props; + + const [open, setOpen] = useState(false); + + const toggleOpen = useCallback(() => setOpen((prevOpen) => !prevOpen), []); + + return ( + <div + className={`notion-block notion-toggle ${getColorCss(color)} ${ + open ? "notion-toggle-open" : "" + }`} + aria-expanded={open} + > + <div className="notion-toggle-content"> + <button onClick={toggleOpen} className="notion-toggle-button"> + <div + className={`notion-toggle-button-arrow ${ + open ? "notion-toggle-button-arrow-opened" : "" + }`} + /> + </button> + <p> + <RichText props={texts} /> + </p> + </div> + + {open && children} + </div> + ); +}; + +export default Toggle; +``` + +## 사용 예시 + +Toggle 블록을 사용하는 예시는 다음과 같습니다: + +```jsx +import { Notion } from "react-notion-custom"; + +function MyNotionPage({ blocks }) { + return ( + <Notion> + <Notion.Blocks blocks={blocks} /> + </Notion> + ); +} +``` + +여기서 `blocks`는 Notion API로부터 받아온 블록 데이터 배열입니다. + +## 상태 관리 + +Toggle 블록은 내부적으로 `useState` 훅을 사용하여 열림/닫힘 상태를 관리합니다. `open` 상태 변수는 토글의 현재 상태를 나타내며, `toggleOpen` 함수는 이 상태를 전환합니다. + +## 스타일링 + +Toggle 블록의 스타일은 다음 CSS 클래스를 통해 커스터마이즈할 수 있습니다: + +- `.notion-block`: 모든 Notion 블록에 적용되는 기본 스타일 +- `.notion-toggle`: Toggle 블록 특정 스타일 +- `.notion-toggle-open`: 토글이 열린 상태일 때의 스타일 +- `.notion-toggle-content`: 토글 내용의 스타일 +- `.notion-toggle-button`: 토글 버튼의 스타일 +- `.notion-toggle-button-arrow`: 토글 화살표의 스타일 + +추가적인 스타일링이 필요한 경우, 이 클래스들을 대상으로 CSS를 작성하면 됩니다. 예를 들어: + +```css +.notion-toggle { + margin-bottom: 8px; +} + +.notion-toggle-button { + cursor: pointer; + background: none; + border: none; + padding: 0; + margin-right: 4px; +} + +.notion-toggle-button-arrow { + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #333; + transition: transform 0.3s ease; +} + +.notion-toggle-button-arrow-opened { + transform: rotate(180deg); +} +``` + +## 중첩 지원 + +Toggle 블록은 다른 블록을 포함할 수 있습니다. 이는 `children` prop을 통해 처리됩니다. 토글이 열린 상태일 때만 `children`이 렌더링됩니다. + +## 접근성 고려사항 + +- `aria-expanded` 속성을 사용하여 토글의 현재 상태를 스크린 리더에 알립니다. +- 키보드 네비게이션을 지원하기 위해 토글 버튼에 `tabIndex={0}`를 추가하는 것이 좋습니다. +- 토글 버튼에 적절한 `aria-label`을 제공하여 그 기능을 명확히 설명하는 것이 좋습니다. + +## 주의사항 + +- 토글 내부에 너무 많은 콘텐츠를 넣으면 사용자 경험이 저하될 수 있으므로 적절한 양의 콘텐츠만 포함하는 것이 좋습니다. +- 토글의 열림/닫힘 상태는 서버에 저장되지 않으므로, 페이지를 새로고침하면 모든 토글이 기본 상태(닫힘)로 돌아갑니다. +- 깊은 수준의 중첩된 토글은 사용자를 혼란스럽게 할 수 있으므로 가능한 한 중첩 수준을 제한하는 것이 좋습니다. diff --git a/packages/docs/hooks/useIsMobile.ts b/packages/docs/hooks/useIsMobile.ts new file mode 100644 index 0000000..a47e6d5 --- /dev/null +++ b/packages/docs/hooks/useIsMobile.ts @@ -0,0 +1,22 @@ +"use client"; + +import { useState, useEffect } from "react"; + +const useIsMobile = () => { + const [isMobile, setIsMobile] = useState(false); + + useEffect(() => { + const checkIsMobile = () => { + setIsMobile(window.innerWidth < 768); + }; + + checkIsMobile(); + window.addEventListener("resize", checkIsMobile); + + return () => window.removeEventListener("resize", checkIsMobile); + }, []); + + return isMobile; +}; + +export default useIsMobile; diff --git a/packages/docs/lib/generateTOC.ts b/packages/docs/lib/generateTOC.ts new file mode 100644 index 0000000..b2537d4 --- /dev/null +++ b/packages/docs/lib/generateTOC.ts @@ -0,0 +1,19 @@ +export interface TOCItem { + id: string; + title: string; +} + +export function generateTOC(content: string): TOCItem[] { + const lines = content.split("\n"); + const toc: TOCItem[] = []; + + lines.forEach((line) => { + if (line.startsWith("<h2>")) { + const title = line.slice(4, -5).trim(); + const id = title.toLowerCase().replace(/[^a-z0-9가-힣]+/g, "-"); + toc.push({ id, title }); + } + }); + + return toc; +} diff --git a/packages/docs/lib/mdx.ts b/packages/docs/lib/mdx.ts new file mode 100644 index 0000000..587d0c6 --- /dev/null +++ b/packages/docs/lib/mdx.ts @@ -0,0 +1,122 @@ +import fs from "fs"; +import path from "path"; +import matter from "gray-matter"; +import { remark } from "remark"; +import html from "remark-html"; +import { getGroupOrder, GroupId } from "@/constants/group"; + +const contentDirectory = path.join(process.cwd(), "content", "guide"); + +interface DocumentData { + slug: string; + content: string; + title: string; + group: string; + prevDocument: { slug: string; title: string; group: string } | null; + nextDocument: { slug: string; title: string; group: string } | null; +} + +export async function getDocumentBySlug( + lang: string, + group: string, + slug: string, +): Promise<DocumentData> { + const notFoundDocument: DocumentData = { + slug: "", + content: "<p>Document not found</p>", + title: "Not Found", + group: "", + prevDocument: null, + nextDocument: null, + }; + + if (!lang || !group || !slug) { + return notFoundDocument; + } + + const groupOrder = getGroupOrder(group as GroupId); + const groupDir = path.join(contentDirectory, lang, `${groupOrder}. ${group}`); + + if (!fs.existsSync(groupDir)) { + return notFoundDocument; + } + + const files = fs.readdirSync(groupDir); + let targetFile = null; + + for (const file of files) { + const filePath = path.join(groupDir, file); + const stat = fs.statSync(filePath); + + if (stat.isFile()) { + const fileContents = fs.readFileSync(filePath, "utf8"); + const { data } = matter(fileContents); + + if (data.slug === slug) { + targetFile = filePath; + break; + } + } + } + + if (!targetFile) { + return notFoundDocument; + } + + const fileContents = fs.readFileSync(targetFile, "utf8"); + const { data, content } = matter(fileContents); + const processedContent = await remark().use(html).process(content); + const contentHtml = processedContent.toString(); + + const allDocuments = getAllDocuments(lang); + const currentIndex = allDocuments.findIndex((doc) => doc.slug === slug); + const prevDocument = currentIndex > 0 ? allDocuments[currentIndex - 1] : null; + const nextDocument = + currentIndex < allDocuments.length - 1 + ? allDocuments[currentIndex + 1] + : null; + + return { + slug, + content: contentHtml, + title: data.title || "Untitled", + group: data.group || "", + prevDocument, + nextDocument, + }; +} + +function getAllDocumentsRecursive(dir: string): any[] { + if (!fs.existsSync(dir)) { + return []; + } + + const files = fs.readdirSync(dir); + let documents: any[] = []; + + files.forEach((file) => { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + + if (stat.isDirectory()) { + documents = documents.concat(getAllDocumentsRecursive(filePath)); + } else if (file.endsWith(".md")) { + const fileContents = fs.readFileSync(filePath, "utf8"); + const { data } = matter(fileContents); + documents.push({ + ...data, + slug: data.slug, + group: data.group, + }); + } + }); + + return documents; +} + +export function getAllDocuments(lang: string) { + const langDir = path.join(contentDirectory, lang); + const documents = getAllDocumentsRecursive(langDir); + + return documents; +} diff --git a/packages/docs/next.config.mjs b/packages/docs/next.config.mjs index 4678774..99cb634 100644 --- a/packages/docs/next.config.mjs +++ b/packages/docs/next.config.mjs @@ -1,4 +1,14 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + async redirects() { + return [ + { + source: "/", + destination: "/en", + permanent: true, + }, + ]; + }, +}; export default nextConfig; diff --git a/packages/docs/package.json b/packages/docs/package.json index ac536f6..d89fc50 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -9,16 +9,26 @@ "lint": "next lint" }, "dependencies": { + "@heroicons/react": "2.1.5", + "@tailwindcss/typography": "0.5.15", + "@types/hast": "3.0.4", + "gray-matter": "4.0.3", + "next": "14.2.11", + "next-themes": "0.3.0", "react": "^18", "react-dom": "^18", - "next": "14.2.11" + "react-markdown": "9.0.1", + "rehype-highlight": "7.0.0", + "rehype-raw": "7.0.0", + "remark": "15.0.1", + "remark-html": "16.0.1" }, "devDependencies": { - "typescript": "^5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "postcss": "^8", - "tailwindcss": "^3.4.1" + "tailwindcss": "^3.4.1", + "typescript": "^5" } } diff --git a/packages/docs/public/logo.svg b/packages/docs/public/logo.svg new file mode 100644 index 0000000..06077de --- /dev/null +++ b/packages/docs/public/logo.svg @@ -0,0 +1,11 @@ +<svg width="478" height="470" viewBox="0 0 478 470" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<rect width="478" height="470" fill="url(#pattern0_103_15)"/> +<rect x="145.641" y="145.957" width="247.402" height="241.426" fill="white"/> +<path d="M371.278 367.419L317.045 368.805L266.6 283.567L255.432 277.1L261.366 264.694L272.863 264.401C281.86 264.171 288.87 261.24 293.895 255.61C298.919 249.98 301.304 242.166 301.048 232.17C300.75 220.507 297.342 211.091 290.823 203.922C284.467 196.582 275.29 193.065 263.294 193.372C255.797 193.564 248.859 196.075 242.48 200.906L246.205 346.609L274.15 353.897L266.568 370.346L178.097 372.608L177.739 358.612L200.727 338.268L197.181 199.564L169.242 192.525L177.074 176.07L218.56 175.009C233.056 174.639 247.288 173.775 261.258 172.417C271.238 171.495 278.727 170.97 283.725 170.842C296.554 170.514 307.944 172.557 317.893 176.971C328.005 181.214 335.826 187.183 341.358 194.877C347.057 202.568 350.029 211.244 350.276 220.908C350.575 232.571 345.686 243.533 335.612 253.793C325.538 264.054 313.15 271.873 298.449 277.251L318.59 282.488L352.562 339.638L378.86 350.97L371.278 367.419Z" fill="black"/> +<defs> +<pattern id="pattern0_103_15" patternContentUnits="objectBoundingBox" width="1" height="1"> +<use xlink:href="#image0_103_15" transform="matrix(0.00195312 0 0 0.00198637 0 -0.00851064)"/> +</pattern> +<image id="image0_103_15" width="512" height="512" xlink:href="data:image/png;base64,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"/> +</defs> +</svg> diff --git a/packages/docs/tailwind.config.ts b/packages/docs/tailwind.config.ts index d43da91..645372a 100644 --- a/packages/docs/tailwind.config.ts +++ b/packages/docs/tailwind.config.ts @@ -1,6 +1,7 @@ import type { Config } from "tailwindcss"; const config: Config = { + darkMode: "class", content: [ "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", @@ -8,12 +9,15 @@ const config: Config = { ], theme: { extend: { + fontFamily: { + sans: ["var(--font-pretendard)"], + }, colors: { background: "var(--background)", foreground: "var(--foreground)", }, }, }, - plugins: [], + plugins: [require("@tailwindcss/typography")], }; export default config;