From 12dc8b4ed194ad5ea217d994c1ed26cd68f8f3b5 Mon Sep 17 00:00:00 2001 From: mohamed yahia Date: Fri, 2 Feb 2024 05:38:02 +0200 Subject: [PATCH] [][l]: Add obsidian canvas support --- components/ObsidianCanvas.tsx | 185 ++++++++++++++++++++++++ components/PdfView.tsx | 64 +++++++++ package-lock.json | 260 +++++++++++++++++++++++++++++----- package.json | 3 +- pages/[[...slug]].tsx | 80 ++++++++--- 5 files changed, 538 insertions(+), 54 deletions(-) create mode 100644 components/ObsidianCanvas.tsx create mode 100644 components/PdfView.tsx diff --git a/components/ObsidianCanvas.tsx b/components/ObsidianCanvas.tsx new file mode 100644 index 000000000..70dde01c8 --- /dev/null +++ b/components/ObsidianCanvas.tsx @@ -0,0 +1,185 @@ +import MdxPage from './MdxPage'; +import dynamic from 'next/dynamic'; + +export default function CanvasElement({ data }) { + // Normalize nodes + const normalizeNodePositions = (nodes) => { + const offsetX = Math.abs(Math.min(...nodes.map((node) => node.x), 0)); + const offsetY = Math.abs(Math.min(...nodes.map((node) => node.y), 0)); + + return nodes.map((node) => ({ + ...node, + x: (node.x + offsetX), + y: (node.y + offsetY), + })); + }; + + // Function to render the different types of nodes based on the node type + const renderNodeContent = (node) => { + switch (node.type) { + case 'text': + return ( +
+ +
+ ); + case 'file': + if (node.file.endsWith('.md') || node.file.endsWith('.mdx')) { + return ( +
+ +
+ ); + } + if (node.file.endsWith('.pdf')) { + const PdfView = dynamic(import('@/components/PdfView'), { + ssr: false, + }); + return ( +
+ +
+ ); + } + return ( +
+ {`File: +
+ ); + case 'link': + const [_, id] = node.url.split('='); + return ( +
+ +
+ ); + + default: + return null; + } + }; + + const getEdgeCoordinates = (node, side) => { + const position = { x: node.x, y: node.y }; + switch (side) { + case 'top': + position.x += node.width / 2; + break; + case 'bottom': + position.x += node.width / 2; + position.y += node.height; + break; + case 'left': + position.y += node.height / 2; + break; + case 'right': + position.x += node.width; + position.y += node.height / 2; + break; + default: + // Handle unexpected side value if necessary + break; + } + return position; + }; + + const normalizedNodes = normalizeNodePositions(data.nodes); + + const renderNodes = normalizedNodes.map((node, index) => { + return ( + <> + {node.file &&
{node.file}
} +
+ {renderNodeContent(node)} +
+ + ); + }); + + const renderEdges = data.edges.map((edge) => { + const fromNode = normalizedNodes.find((node) => node.id === edge.fromNode); + const toNode = normalizedNodes.find((node) => node.id === edge.toNode); + + if (!fromNode || !toNode) { + console.warn(`Nodes for edge ${edge.id} not found.`); + return null; + } + + const fromPosition = getEdgeCoordinates(fromNode, edge.fromSide); + const toPosition = getEdgeCoordinates(toNode, edge.toSide); + + const arrowheadMarkerId = `arrowhead-${edge.id}`; + + return ( + + + + + + + + {edge.label && ( + + {edge.label} + + )} + + ); + }); + + return ( +
+
+ {renderEdges} + {renderNodes} +
+
+ ); +} diff --git a/components/PdfView.tsx b/components/PdfView.tsx new file mode 100644 index 000000000..fa7268e4c --- /dev/null +++ b/components/PdfView.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react'; +import { Document, Page } from 'react-pdf'; +import 'react-pdf/dist/Page/AnnotationLayer.css'; +import 'react-pdf/dist/Page/TextLayer.css'; + +import { pdfjs } from 'react-pdf'; + +pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`; + +export default function PdfView({ + filePath, + width, + height, +}: { + filePath: string; + width: number; + height: number; +}) { + const [numPages, setNumPages] = useState(); + const [pageNumber, setPageNumber] = useState(1); + + function onDocumentLoadSuccess({ numPages }: { numPages: number }): void { + setNumPages(numPages); + } + + const handleNextPage = () => { + if (pageNumber < numPages) { + setPageNumber(pageNumber + 1); + } + }; + + const handlePrevPage = () => { + if (pageNumber > 1) { + setPageNumber(pageNumber - 1); + } + }; + + return ( +
+ + + +
+ +

+ Page {pageNumber} of {numPages} +

+ +
+
+ ); +} diff --git a/package-lock.json b/package-lock.json index 174691911..c77636e84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "date-fns": "^2.29.3", "gray-matter": "^4.0.3", "hastscript": "^7.2.0", - "mddb": "^0.9.1", + "mddb": "^0.9.3", "mdx-mermaid": "2.0.0-rc7", "next": "13.3.0", "next-mdx-remote": "^4.4.1", @@ -31,6 +31,7 @@ "next-seo": "^5.15.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-pdf": "^7.7.0", "rehype-autolink-headings": "^6.1.1", "rehype-katex": "^6.0.2", "rehype-prism-plus": "^1.5.1", @@ -2037,11 +2038,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, "node_modules/array-iterate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", @@ -2253,6 +2249,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2266,6 +2270,20 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -2376,14 +2394,6 @@ "node": ">=10.16.0" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/cacache": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", @@ -2493,6 +2503,21 @@ } ] }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -3522,6 +3547,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -4093,6 +4130,11 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -4106,6 +4148,20 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/express/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -4374,9 +4430,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.6", @@ -6486,6 +6545,14 @@ "node": ">=10" } }, + "node_modules/make-cancellable-promise": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz", + "integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==", + "funding": { + "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -6508,6 +6575,14 @@ "semver": "bin/semver.js" } }, + "node_modules/make-event-props": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz", + "integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==", + "funding": { + "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" + } + }, "node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", @@ -7019,9 +7094,9 @@ } }, "node_modules/mddb": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/mddb/-/mddb-0.9.1.tgz", - "integrity": "sha512-cZYP6OXpVRXIChgkA9u2T2/EavZyhj4EaqiU5kAPqCswN/I9ZSc0yKr0cqOxzXn3ThL2WodTSYjBkA/rBVKsMw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/mddb/-/mddb-0.9.3.tgz", + "integrity": "sha512-50uKI3enXRrBC6G1EbyNXHSzitk2L0uvldXVyy9kJvFrbGg+GzpJpDyxTRtpO1EWvrzrcfyfStDz3wnqg4B6VQ==", "dependencies": { "@portaljs/remark-wiki-link": "^1.0.4", "@types/micromatch": "^4.0.6", @@ -7098,6 +7173,22 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, + "node_modules/merge-refs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.2.2.tgz", + "integrity": "sha512-RwcT7GsQR3KbuLw1rRuodq4Nt547BKEBkliZ0qqsrpyNne9bGTFtsFIsIpx82huWhcl3kOlOlH4H0xkPk/DqVw==", + "funding": { + "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -7888,6 +7979,18 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -8059,6 +8162,12 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", @@ -8745,6 +8854,27 @@ "node": ">=8" } }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pdfjs-dist": { + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -9129,20 +9259,6 @@ "node": ">=14.1.0" } }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9193,6 +9309,14 @@ "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -9892,6 +10016,35 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/react-pdf": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.0.tgz", + "integrity": "sha512-704ObLnRDm5lixL4e6NXNLaincBHGNLo+NGdbO3rEXE963NlNzwLxFpmKcbdXHAMQL4rYJQWb1L0w5IL6y8Osw==", + "dependencies": { + "clsx": "^2.0.0", + "dequal": "^2.0.3", + "make-cancellable-promise": "^1.3.1", + "make-event-props": "^1.6.0", + "merge-refs": "^1.2.1", + "pdfjs-dist": "3.11.174", + "prop-types": "^15.6.2", + "tiny-invariant": "^1.0.0", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -10684,6 +10837,37 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -12193,6 +12377,14 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/package.json b/package.json index e84b7307e..c86356b24 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "date-fns": "^2.29.3", "gray-matter": "^4.0.3", "hastscript": "^7.2.0", - "mddb": "^0.9.1", + "mddb": "^0.9.3", "mdx-mermaid": "2.0.0-rc7", "next": "13.3.0", "next-mdx-remote": "^4.4.1", @@ -34,6 +34,7 @@ "next-seo": "^5.15.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-pdf": "^7.7.0", "rehype-autolink-headings": "^6.1.1", "rehype-katex": "^6.0.2", "rehype-prism-plus": "^1.5.1", diff --git a/pages/[[...slug]].tsx b/pages/[[...slug]].tsx index 76a2f0d5a..956aef3b1 100644 --- a/pages/[[...slug]].tsx +++ b/pages/[[...slug]].tsx @@ -9,12 +9,14 @@ import computeFields from "@/lib/computeFields"; import parse from "@/lib/markdown"; import siteConfig from "@/config/siteConfig"; import type { CustomAppProps } from "./_app"; +import CanvasElement from "@/components/ObsidianCanvas"; interface SlugPageProps extends CustomAppProps { source: any; + type: 'md' | 'canvas'; } -export default function Page({ source, meta }: SlugPageProps) { +export default function Page({ source, type, meta }: SlugPageProps) { source = JSON.parse(source); const seoImages = (() => { @@ -46,7 +48,11 @@ export default function Page({ source, meta }: SlugPageProps) { images: seoImages, }} /> - + {type === "md" ? ( + + ) : ( + + )} ); } @@ -61,30 +67,66 @@ export const getStaticProps: GetStaticProps = async ({ const filePath = dbFile!.file_path; const frontMatter = dbFile!.metadata ?? {}; - const source = fs.readFileSync(filePath, { encoding: "utf-8" }); - const { mdxSource } = await parse(source, "mdx", {}); + const type = dbFile!.extension === 'canvas' ? 'canvas' : 'md'; + const rawFile = fs.readFileSync(filePath, { encoding: 'utf-8' }); + let source; + let frontMatterWithComputedFields: any = {}; + const siteMap: Array = []; + if (type === 'md') { + const { mdxSource } = await parse(rawFile, 'mdx', {}); + source = mdxSource; + // TODO temporary replacement for contentlayer's computedFields + frontMatterWithComputedFields = await computeFields({ + frontMatter, + urlPath, + filePath, + source: rawFile, + }); - // TODO temporary replacement for contentlayer's computedFields - const frontMatterWithComputedFields = await computeFields({ - frontMatter, - urlPath, - filePath, - source, - }); + if (frontMatterWithComputedFields?.showSidebar) { + const allPages = await mddb.getFiles({ extensions: ['md', 'mdx'] }); + const pages = allPages.filter((p) => !p.metadata?.isDraft); + pages.forEach((page) => { + addPageToSitemap(page, siteMap); + }); + } + } - const siteMap: Array = []; + if (type === 'canvas') { + const canvas = JSON.parse(rawFile); + const nodesPromises = canvas.nodes.map(async (node: any) => { + if (node.type === 'text') { + const { mdxSource } = await parse(node.text, 'mdx', {}); + return { + ...node, + source: mdxSource, + }; + } + if (node.type === 'file' && node.file.endsWith('.md')) { + const rawFile = fs.readFileSync('content/' + node.file, { + encoding: 'utf-8', + }); + const { mdxSource } = await parse(rawFile, 'mdx', {}); - if (frontMatterWithComputedFields?.showSidebar) { - const allPages = await mddb.getFiles({ extensions: ["md", "mdx"] }); - const pages = allPages.filter((p) => !p.metadata?.isDraft); - pages.forEach((page) => { - addPageToSitemap(page, siteMap); + return { + ...node, + source: mdxSource, + }; + } + return node; }); + + const nodes = await Promise.all(nodesPromises); + source = { + ...canvas, + nodes, + }; } return { props: { - source: JSON.stringify(mdxSource), + type, + source: JSON.stringify(source), meta: frontMatterWithComputedFields, siteMap, }, @@ -93,7 +135,7 @@ export const getStaticProps: GetStaticProps = async ({ export const getStaticPaths: GetStaticPaths = async () => { const mddb = await clientPromise; - const allDocuments = await mddb.getFiles({ extensions: ["md", "mdx"] }); + const allDocuments = await mddb.getFiles({ extensions: ["md", "mdx", "canvas"] }); const paths = allDocuments .filter((page) => page.metadata?.isDraft !== true)