diff --git a/docs/details/graphs/bar.mdx b/docs/details/graphs/bar.mdx new file mode 100644 index 00000000000..ce6c34384ab --- /dev/null +++ b/docs/details/graphs/bar.mdx @@ -0,0 +1,28 @@ +--- +tags: + - TODO +keywords: + - TODO +description: TODO +sidebar_label: Bar Chart +sidebar_position: 1 +--- + +# Neural Magic Bar Chart + +TODO + +## Chart + + + +## Controls + +TODO diff --git a/docs/details/graphs/index.mdx b/docs/details/graphs/index.mdx new file mode 100644 index 00000000000..d278386352c --- /dev/null +++ b/docs/details/graphs/index.mdx @@ -0,0 +1,14 @@ +--- +tags: + - TODO +keywords: + - TODO +description: TODO +sidebar_position: 9 +--- + +# Graph Creation + +TODO + + diff --git a/docs/details/graphs/line.mdx b/docs/details/graphs/line.mdx new file mode 100644 index 00000000000..a520f69c234 --- /dev/null +++ b/docs/details/graphs/line.mdx @@ -0,0 +1,25 @@ +--- +tags: + - TODO +keywords: + - TODO +description: TODO +sidebar_label: Line Chart +sidebar_position: 1 +--- + +# Line Chart + +TODO + +## Chart + + + +## Controls + +TODO diff --git a/docs/details/graphs/neural-network.mdx b/docs/details/graphs/neural-network.mdx new file mode 100644 index 00000000000..9460f024885 --- /dev/null +++ b/docs/details/graphs/neural-network.mdx @@ -0,0 +1,21 @@ +--- +tags: + - TODO +keywords: + - TODO +description: TODO +sidebar_label: Neural Network +sidebar_position: 1 +--- + +# Neural Network + +TODO + +## Chart + + + +## Controls + +TODO diff --git a/docs/details/graphs/tradeoff-triangle.mdx b/docs/details/graphs/tradeoff-triangle.mdx new file mode 100644 index 00000000000..d6d9f03153f --- /dev/null +++ b/docs/details/graphs/tradeoff-triangle.mdx @@ -0,0 +1,21 @@ +--- +tags: + - TODO +keywords: + - TODO +description: TODO +sidebar_label: Tradeoff Triangle +sidebar_position: 1 +--- + +# Tradeoff Triangle + +TODO + +## Chart + + + +## Controls + +TODO diff --git a/package-lock.json b/package-lock.json index 7a411c43c73..8567b6564da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,17 +14,28 @@ "@docusaurus/preset-classic": "^3.2.1", "@docusaurus/theme-search-algolia": "^3.2.1", "@mdx-js/react": "^3.0.0", + "@nivo/bar": "^0.85.1", + "@nivo/boxplot": "^0.85.1", + "@nivo/core": "^0.85.1", + "@nivo/line": "^0.85.1", + "@nivo/pie": "^0.85.1", + "@nivo/radar": "^0.85.1", + "@nivo/scatterplot": "^0.85.1", "clsx": "^2.0.0", + "crypto-js": "^4.2.0", "docusaurus-plugin-sass": "^0.2.5", "marked": "^11.1.1", + "mathjs": "^12.4.1", "prism-react-renderer": "^2.3.0", "react": "^18.0.0", "react-dom": "^18.0.0", - "sass": "^1.70.0" + "sass": "^1.70.0", + "seedrandom": "^3.0.5" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.2.1", - "@docusaurus/types": "^3.2.1" + "@docusaurus/types": "^3.2.1", + "prettier": "^3.2.5" }, "engines": { "node": ">=18.0" @@ -2929,6 +2940,306 @@ "react": ">=16" } }, + "node_modules/@nivo/annotations": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.85.1.tgz", + "integrity": "sha512-+YVFKMokf6MMXsztpEoOoFwG+XcEJV90xezuqJ8FmS0hgEzJ8xTeWNxPRWfrvxndMXNrau4QIRU5GrumBmiy4Q==", + "dependencies": { + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/prop-types": "^15.7.2", + "lodash": "^4.17.21", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/arcs": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/arcs/-/arcs-0.85.1.tgz", + "integrity": "sha512-UwwiSXHWY8cIgi3FADQJX8gyFCJfdx1N80MzxFGuHOYbTcBmsRMMbZYfqXJ5z/x61ulTkLcv/yVvlTEOCKMlcQ==", + "dependencies": { + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-shape": "^2.0.0", + "d3-shape": "^1.3.5" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/axes": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.85.1.tgz", + "integrity": "sha512-qhqyamgH8CAdOGEiLwwnqMpPKN6bv9FmKr/75UrNcAvWbU0PZ3unZJGKNkuFzlVAI9/RVvOUvXEE0rRBqV93qg==", + "dependencies": { + "@nivo/core": "0.85.1", + "@nivo/scales": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-format": "^1.4.1", + "@types/d3-time-format": "^2.3.1", + "@types/prop-types": "^15.7.2", + "d3-format": "^1.4.4", + "d3-time-format": "^3.0.0", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/bar": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/bar/-/bar-0.85.1.tgz", + "integrity": "sha512-42Hjvt5YJ9O5Ew+SrZ+jd8NR30odSRuHS/B4tpsL/Yqg2MjmpB+niRMuybEhUAuhQ0aCKvwUHlocjwRRzNXqnA==", + "dependencies": { + "@nivo/annotations": "0.85.1", + "@nivo/axes": "0.85.1", + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@nivo/legends": "0.85.1", + "@nivo/scales": "0.85.1", + "@nivo/tooltip": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^2.0.0", + "d3-scale": "^4.0.2", + "d3-shape": "^1.3.5", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/boxplot": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/boxplot/-/boxplot-0.85.1.tgz", + "integrity": "sha512-v4QGdvW5+6x7tBTvoGTfAUtSTqU7TdFJhpKQ9FIrNs26Xc1YSy0HgWZsUbeigotKLskqYDuI2CjafQ/MvzWvRQ==", + "dependencies": { + "@nivo/annotations": "0.85.1", + "@nivo/axes": "0.85.1", + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@nivo/legends": "0.85.1", + "@nivo/scales": "0.85.1", + "@nivo/tooltip": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^2.0.0", + "d3-scale": "^4.0.2", + "d3-shape": "^1.3.5", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/colors": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.85.1.tgz", + "integrity": "sha512-61qG98cfyku0fTJTdtCTS3zBQKt88URh4FAvlQIoifvKg0607S2Gz5l7P9KJfN7xEK5tmE4bRaOMmjc4AZS2Kg==", + "dependencies": { + "@nivo/core": "0.85.1", + "@types/d3-color": "^3.0.0", + "@types/d3-scale": "^4.0.8", + "@types/d3-scale-chromatic": "^3.0.0", + "@types/prop-types": "^15.7.2", + "d3-color": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.0.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/core": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.85.1.tgz", + "integrity": "sha512-366bc4hBicsitcinQyKGfUPpifk5W60RAjwZ4sQkY8R6OzwPMgY+eu/sfPZTNcY7rsleGg8whX0A2dBg2czWMA==", + "dependencies": { + "@nivo/recompose": "0.85.0", + "@nivo/tooltip": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-shape": "^2.0.0", + "d3-color": "^3.1.0", + "d3-format": "^1.4.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.0.0", + "d3-shape": "^1.3.5", + "d3-time-format": "^3.0.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nivo/donate" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/legends": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.85.1.tgz", + "integrity": "sha512-v2DRiUieo3/iV1Fft3i9pbGTkE5arXzmw+p1ptb4xfBBPpd0hSAHvaePXDY370G31dsh2v5LouL97u+q12li4Q==", + "dependencies": { + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@types/d3-scale": "^4.0.8", + "@types/prop-types": "^15.7.2", + "d3-scale": "^4.0.2", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/line": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.85.1.tgz", + "integrity": "sha512-BLswEMiBiFxpHaRoiKp7d3S4P3gzj0OYVBojFEEG+g19lmIEeTTc7aZsXz2pTz/NdzM6fwZqTD3llIhl6LfXFg==", + "dependencies": { + "@nivo/annotations": "0.85.1", + "@nivo/axes": "0.85.1", + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@nivo/legends": "0.85.1", + "@nivo/scales": "0.85.1", + "@nivo/tooltip": "0.85.1", + "@nivo/voronoi": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "d3-shape": "^1.3.5", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/pie": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/pie/-/pie-0.85.1.tgz", + "integrity": "sha512-2dSQ7YIc6BLkYFadg+r6uOR5FXOCRSCWAYEIlvMapAvYqQ6/ie3ZnMtEB9idiucy8F4I/zF5C08OSr2jE4DJ9g==", + "dependencies": { + "@nivo/arcs": "0.85.1", + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@nivo/legends": "0.85.1", + "@nivo/tooltip": "0.85.1", + "@types/d3-shape": "^2.0.0", + "d3-shape": "^1.3.5" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/radar": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/radar/-/radar-0.85.1.tgz", + "integrity": "sha512-WJz+YATb4PadjImI0bgW5JLLowpZ0OKQ/yVoUzprAjOB3zm2ABKM6SAEsIhj/GNKhwBhBWFHJMpAL2ECAf2TYA==", + "dependencies": { + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@nivo/legends": "0.85.1", + "@nivo/tooltip": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^2.0.0", + "d3-scale": "^4.0.2", + "d3-shape": "^1.3.5" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/recompose": { + "version": "0.85.0", + "resolved": "https://registry.npmjs.org/@nivo/recompose/-/recompose-0.85.0.tgz", + "integrity": "sha512-UptKwVJ9mlGQKn4a/JiORWbZgo6hT+qEpKBKIs9BUHRIW0a4T0BIE2PA+uDMPpNxzNFgOCu/y8iM5Rhs6QmrmA==", + "dependencies": { + "@types/prop-types": "^15.7.2", + "@types/react-lifecycles-compat": "^3.0.1", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/scales": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.85.1.tgz", + "integrity": "sha512-zObimCMjbbioMpQtVSGmr52OTn+BVJZsyhKHFx7CK57RA+OW/9lGnvqzc0rnFxl8WBqvHk7wReE5UI8xva/6Zw==", + "dependencies": { + "@types/d3-scale": "^4.0.8", + "@types/d3-time": "^1.1.1", + "@types/d3-time-format": "^3.0.0", + "d3-scale": "^4.0.2", + "d3-time": "^1.0.11", + "d3-time-format": "^3.0.0", + "lodash": "^4.17.21" + } + }, + "node_modules/@nivo/scales/node_modules/@types/d3-time-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-3.0.4.tgz", + "integrity": "sha512-or9DiDnYI1h38J9hxKEsw513+KVuFbEVhl7qdxcaudoiqWWepapUen+2vAriFGexr6W5+P4l9+HJrB39GG+oRg==" + }, + "node_modules/@nivo/scatterplot": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/scatterplot/-/scatterplot-0.85.1.tgz", + "integrity": "sha512-Ds0c89M3Aa+gzLuQLFc7JMkwnAbactnHpNivxFYhtBH2k5rjrTEazhXapqe8W8gbScIV2dTVVdj2KYzb5tq3kw==", + "dependencies": { + "@nivo/annotations": "0.85.1", + "@nivo/axes": "0.85.1", + "@nivo/colors": "0.85.1", + "@nivo/core": "0.85.1", + "@nivo/legends": "0.85.1", + "@nivo/scales": "0.85.1", + "@nivo/tooltip": "0.85.1", + "@nivo/voronoi": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^2.0.0", + "d3-scale": "^4.0.2", + "d3-shape": "^1.3.5", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/tooltip": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.85.1.tgz", + "integrity": "sha512-lX0/MuDI9HvGzYxAtE3mnriYEgFHBWf7d5BMqUifJZIyg82XkI9g3z6vwAwPKRJ52rON9Yhik42+gwFMFj3BrA==", + "dependencies": { + "@nivo/core": "0.85.1", + "@react-spring/web": "9.4.5 || ^9.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, + "node_modules/@nivo/voronoi": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@nivo/voronoi/-/voronoi-0.85.1.tgz", + "integrity": "sha512-HJuc1Lhc7RhJyZCnn2eB1nqX6tsczUY4Z1YY3rl1Gy5HfW1vpoJZHQtWzelnvVcpj3qTrwI9QGLmDYE12HAeOQ==", + "dependencies": { + "@nivo/core": "0.85.1", + "@types/d3-delaunay": "^5.3.0", + "@types/d3-scale": "^4.0.8", + "d3-delaunay": "^5.3.0", + "d3-scale": "^4.0.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 19.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3003,6 +3314,66 @@ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" }, + "node_modules/@react-spring/animated": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", + "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "dependencies": { + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", + "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/shared": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", + "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "dependencies": { + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", + "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", + "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/core": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -3351,6 +3722,57 @@ "@types/node": "*" } }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-delaunay": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-5.3.4.tgz", + "integrity": "sha512-GEQuDXVKQvHulQ+ecKyCubOmVjXrifAj7VR26rWVAER/IbWemaT/Tmo84ESiTtoDghg5ILdMZH7pYXQEt/Vu9A==" + }, + "node_modules/@types/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-mLxrC1MSWupOSncXN/HOlWUAAIffAEBaI4+PKy2uMPsKe4FNZlk7qrbTjmzJXITQQqBHivaks4Td18azgqnotA==" + }, + "node_modules/@types/d3-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-2.0.4.tgz", + "integrity": "sha512-jjZVLBjEX4q6xneKMmv62UocaFJFOTQSb/1aTzs3m3ICTOFoVaqGBHpNLm/4dVi0/FTltfBKgmOK1ECj3/gGjA==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", + "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==" + }, + "node_modules/@types/d3-shape": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.1.7.tgz", + "integrity": "sha512-HedHlfGHdwzKqX9+PiQVXZrdmGlwo7naoefJP7kCNk4Y7qcpQt1tUaoRa6qn0kbTdlaIHGO7111qLtb/6J8uuw==", + "dependencies": { + "@types/d3-path": "^2" + } + }, + "node_modules/@types/d3-time": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.1.4.tgz", + "integrity": "sha512-JIvy2HjRInE+TXOmIGN5LCmeO0hkFZx5f9FZ7kiN+D+YTcc8pptsiLiuHsvwxwC7VVKmJ2ExHUgNlAiV7vQM9g==" + }, + "node_modules/@types/d3-time-format": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.3.4.tgz", + "integrity": "sha512-xdDXbpVO74EvadI3UDxjxTdR6QIxm1FKzEA/+F8tL4GWWUg/hgvBqf6chql64U5A9ZUGWo7pEu4eNlyLwbKdhg==" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -3553,6 +3975,14 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-1CM48Y9ztL5S4wjt7DK2izrkgPp/Ql0zCJu/vHzhgl7J+BD4UbSGjHN1M2TlePms472JvOazUtAO1/G3oFZqIQ==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-router": { "version": "5.1.20", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", @@ -4820,6 +5250,18 @@ "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" }, + "node_modules/complex.js": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz", + "integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4941,9 +5383,9 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -5092,6 +5534,11 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "node_modules/crypto-random-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", @@ -5378,6 +5825,113 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-5.3.0.tgz", + "integrity": "sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w==", + "dependencies": { + "delaunator": "4" + } + }, + "node_modules/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale/node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" + }, + "node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "dependencies": { + "d3-time": "1 - 2" + } + }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -5399,6 +5953,11 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, "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", @@ -5532,6 +6091,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delaunator": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-4.0.1.tgz", + "integrity": "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag==" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5874,6 +6438,11 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "node_modules/escape-latex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -6094,16 +6663,16 @@ } }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -7583,6 +8152,14 @@ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", @@ -7888,6 +8465,11 @@ "node": ">=0.10.0" } }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" + }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -8225,6 +8807,40 @@ "node": ">= 18" } }, + "node_modules/mathjs": { + "version": "12.4.1", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.4.1.tgz", + "integrity": "sha512-welnW3khgwYjPYvECFHO+xkCxAx9IKIIPDDWPi8B5rKAvmgoEHnQX9slEmHKZTNaJiE+OS4qrJJcB4sfDn/4sw==", + "dependencies": { + "@babel/runtime": "^7.24.0", + "complex.js": "^2.1.1", + "decimal.js": "^10.4.3", + "escape-latex": "^1.2.0", + "fraction.js": "4.3.4", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^4.1.1" + }, + "bin": { + "mathjs": "bin/cli.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mathjs/node_modules/fraction.js": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.4.tgz", + "integrity": "sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/mdast-util-directive": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", @@ -11625,6 +12241,21 @@ "postcss": "^8.2.15" } }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", @@ -12037,6 +12668,11 @@ "react": "^16.13.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, "node_modules/react-loadable": { "name": "@docusaurus/react-loadable", "version": "5.5.2", @@ -12802,6 +13438,11 @@ "node": ">=4" } }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -13708,6 +14349,11 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -13818,6 +14464,14 @@ "node": ">= 0.6" } }, + "node_modules/typed-function": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.1.1.tgz", + "integrity": "sha512-Pq1DVubcvibmm8bYcMowjVnnMwPVMeh0DIdA8ad8NZY2sJgapANJmiigSUwlt+EgXxpfIv8MWrQXTIzkfYZLYQ==", + "engines": { + "node": ">= 14" + } + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -14426,9 +15080,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", diff --git a/package.json b/package.json index 3b6ce8d6571..d23ff3c62be 100644 --- a/package.json +++ b/package.json @@ -20,17 +20,28 @@ "@docusaurus/preset-classic": "^3.2.1", "@docusaurus/theme-search-algolia": "^3.2.1", "@mdx-js/react": "^3.0.0", + "@nivo/bar": "^0.85.1", + "@nivo/boxplot": "^0.85.1", + "@nivo/core": "^0.85.1", + "@nivo/line": "^0.85.1", + "@nivo/pie": "^0.85.1", + "@nivo/radar": "^0.85.1", + "@nivo/scatterplot": "^0.85.1", "clsx": "^2.0.0", + "crypto-js": "^4.2.0", "docusaurus-plugin-sass": "^0.2.5", "marked": "^11.1.1", + "mathjs": "^12.4.1", "prism-react-renderer": "^2.3.0", "react": "^18.0.0", "react-dom": "^18.0.0", - "sass": "^1.70.0" + "sass": "^1.70.0", + "seedrandom": "^3.0.5" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.2.1", - "@docusaurus/types": "^3.2.1" + "@docusaurus/types": "^3.2.1", + "prettier": "^3.2.5" }, "browserslist": { "production": [ diff --git a/public/img/transparent.png b/public/img/transparent.png new file mode 100644 index 00000000000..d5176a5f81e Binary files /dev/null and b/public/img/transparent.png differ diff --git a/src/components/github-releases/index.jsx b/src/components/github-releases/index.jsx index 87b20424dbd..4a5a27c2718 100644 --- a/src/components/github-releases/index.jsx +++ b/src/components/github-releases/index.jsx @@ -1,90 +1,97 @@ -import React, { useState, useEffect } from 'react'; -import { marked } from 'marked'; -import styles from './styles.module.scss'; - +import React, { useState, useEffect } from "react"; +import { marked } from "marked"; +import styles from "./styles.module.scss"; const ReleaseNotes = ({ content, repo }) => { - const renderer = new marked.Renderer(); - renderer.heading = (text, level) => { - return `${text}`; - }; - renderer.text = (text) => { - return text.replace(/#\d+/g, (match) => { - const issueNumber = match.slice(1); - return `${match}`; - }); - }; + const renderer = new marked.Renderer(); + renderer.heading = (text, level) => { + return `${text}`; + }; + renderer.text = (text) => { + return text.replace(/#\d+/g, (match) => { + const issueNumber = match.slice(1); + return `${match}`; + }); + }; - marked.setOptions({ renderer }); + marked.setOptions({ renderer }); - const createMarkup = () => { - return { __html: marked.parse(content) } - } + const createMarkup = () => { + return { __html: marked.parse(content) }; + }; - return ( -
- ); -} + return
; +}; const Index = ({ repo }) => { - const [releases, setReleases] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); + const [releases, setReleases] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); - useEffect(() => { - const fetchReleases = async () => { - setIsLoading(true); - setError(null); - try { - const response = await fetch(`https://api.github.com/repos/${repo}/releases`); - if (!response.ok) { - // Handling different types of errors - if (response.status === 403) { - setError("API rate limit exceeded. Please try again later."); - } else { - setError(`Failed to fetch data: ${response.statusText}`); - } - throw new Error(`Error: ${response.status}`); - } - const data = await response.json(); - setReleases(data); - } catch (error) { - console.error('Fetching error:', error); - } - setIsLoading(false); - }; - - fetchReleases(); - }, [repo]); + useEffect(() => { + const fetchReleases = async () => { + setIsLoading(true); + setError(null); + try { + const response = await fetch( + `https://api.github.com/repos/${repo}/releases`, + ); + if (!response.ok) { + // Handling different types of errors + if (response.status === 403) { + setError("API rate limit exceeded. Please try again later."); + } else { + setError(`Failed to fetch data: ${response.statusText}`); + } + throw new Error(`Error: ${response.status}`); + } + const data = await response.json(); + setReleases(data); + } catch (error) { + console.error("Fetching error:", error); + } + setIsLoading(false); + }; - if (isLoading) { - return
Loading...
; - } + fetchReleases(); + }, [repo]); - if (error) { - return
Error: {error}
; - } + if (isLoading) { + return ( +
Loading...
+ ); + } + if (error) { return ( -
- {releases.length === 0 ? ( -

No releases found.

- ) : ( - - )} -
+
Error: {error}
); + } + + return ( +
+ {releases.length === 0 ? ( +

No releases found.

+ ) : ( + + )} +
+ ); }; -export default Index; \ No newline at end of file +export default Index; diff --git a/src/components/github-releases/styles.module.scss b/src/components/github-releases/styles.module.scss index 30a0b7e8178..5f1882cbcbc 100644 --- a/src/components/github-releases/styles.module.scss +++ b/src/components/github-releases/styles.module.scss @@ -20,7 +20,7 @@ } .error { - color: #D32F2F; // Material Red + color: #d32f2f; // Material Red } .loading { @@ -46,4 +46,4 @@ color: var(--ifm-font-color-base); margin: 0 0 32px; font-weight: bold; -} \ No newline at end of file +} diff --git a/src/components/glossary/table/index.jsx b/src/components/glossary/table/index.jsx index 0ba0808f94c..771b435881b 100644 --- a/src/components/glossary/table/index.jsx +++ b/src/components/glossary/table/index.jsx @@ -1,27 +1,30 @@ -import React from 'react'; - -import styles from './styles.module.scss'; -import glossaryData from '../../../../glossary'; +import React from "react"; +import styles from "./styles.module.scss"; +import glossaryData from "../../../../glossary"; const GlossaryTable = () => { - return ( -
-
-
Name
-
Definition
-
+ return ( +
+
+
Name
+
Definition
+
- {glossaryData.map(term => ( -
- -
{term.description ? term.description : term.summary}
-
- ))} + {glossaryData.map((term) => ( +
+ +
+ {term.description ? term.description : term.summary} +
- ); -} + ))} +
+ ); +}; -export default GlossaryTable; \ No newline at end of file +export default GlossaryTable; diff --git a/src/components/glossary/table/styles.module.scss b/src/components/glossary/table/styles.module.scss index 95adc0f9825..fab0d03021a 100644 --- a/src/components/glossary/table/styles.module.scss +++ b/src/components/glossary/table/styles.module.scss @@ -37,4 +37,4 @@ border-bottom: 1px solid var(--ifm-toc-border-color); border-top: 1px solid var(--ifm-toc-border-color); font-weight: bold; -} \ No newline at end of file +} diff --git a/src/components/glossary/tool-tip/index.jsx b/src/components/glossary/tool-tip/index.jsx index b7748edc203..3eda45c07eb 100644 --- a/src/components/glossary/tool-tip/index.jsx +++ b/src/components/glossary/tool-tip/index.jsx @@ -1,34 +1,46 @@ -import React, { useState } from 'react'; +import React, { useState } from "react"; -import styles from './styles.module.scss'; +import styles from "./styles.module.scss"; -import glossaryData from '../../../../glossary'; +import glossaryData from "../../../../glossary"; - -const processText = (text) => text.toLowerCase().replace(/[\s_-]/g, ''); +const processText = (text) => text.toLowerCase().replace(/[\s_-]/g, ""); const Tooltip = ({ children, termName }) => { - const [showTooltip, setShowTooltip] = useState(false); - let processedTermName = termName ? processText(termName) : processText(children); - - const term = glossaryData.find((term) => processText(term.label) === processedTermName); - - const content = term ? (term.summary || term.description) : ''; - - return ( - setShowTooltip(true)} - onMouseLeave={() => setShowTooltip(false)}> - - {children} - -
- {content} - {term && More Info} + const [showTooltip, setShowTooltip] = useState(false); + let processedTermName = termName + ? processText(termName) + : processText(children); + + const term = glossaryData.find( + (term) => processText(term.label) === processedTermName, + ); + + const content = term ? term.summary || term.description : ""; + + return ( + setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + > + {children} + +
+ {content} + {term && ( + + More Info + + )}
- ); + ); }; export default Tooltip; diff --git a/src/components/glossary/tool-tip/styles.module.scss b/src/components/glossary/tool-tip/styles.module.scss index 7939590185e..709692aec55 100644 --- a/src/components/glossary/tool-tip/styles.module.scss +++ b/src/components/glossary/tool-tip/styles.module.scss @@ -18,7 +18,9 @@ z-index: 100; opacity: 0; visibility: hidden; - transition: visibility 0.2s, opacity 0.2s ease-in-out; + transition: + visibility 0.2s, + opacity 0.2s ease-in-out; background-color: var(--custom-surface-color); color: var(--ifm-font-color-base); text-decoration: none; diff --git a/src/components/graphs/bar/index.jsx b/src/components/graphs/bar/index.jsx new file mode 100644 index 00000000000..13ab8c8abca --- /dev/null +++ b/src/components/graphs/bar/index.jsx @@ -0,0 +1,170 @@ +import React from "react"; + +const NeuralMagicBar = ({ + children, + file, + data, + testDataType = null, + width = "100%", + height = "400px", + title = null, + titleType = "h2", + subTitle = null, + subTitleType = "h6", + showLegend = true, + valuesLabel = null, + valuesFormat = "#", + valueMax = null, + valueMin = null, + valueStepPercentage = 33.33, + valueSteps = null, + groupsLabel = null, +}) => { + return
NeuralMagicBar
; + + // if (testDataType) { + // data = samples["bar"][testDataType]; + // } + // + // const dataSeries = []; + // const dataLabels = []; + // let colorIndex = 0; + // + // for (const { value, label, index = null } of data) { + // let series = dataSeries.find((series) => series.index === index); + // + // if (!series) { + // series = { + // index, + // color: styling.colors[colorIndex % styling.colors.length], + // }; + // dataSeries.push(series); + // colorIndex += 1; + // } + // + // let dataLabel = dataLabels.find((dataLabel) => dataLabel.label === label); + // + // if (!dataLabel) { + // dataLabel = { label, values: [] }; + // dataLabels.push(dataLabel); + // } + // + // dataLabel.values.push({ value, color: series.color }); + // } + // + // const dataValueMin = Math.min(...data.map((item) => item.value)) * 0.9; + // const dataValueMax = Math.max(...data.map((item) => item.value)) * 1.1; + // const verticalAxisMax = valueMax === null ? dataValueMax : valueMax; + // const verticalAxisMin = valueMin === null ? dataValueMin : valueMin; + // const verticalAxisStrata = []; + // + // if (!valueSteps) { + // for ( + // let percentIncrement = 0; + // percentIncrement <= 100; + // percentIncrement += valueStepPercentage + // ) { + // verticalAxisStrata.push( + // verticalAxisMin + + // (verticalAxisMax - verticalAxisMin) * (percentIncrement / 100), + // ); + // } + // } else { + // verticalAxisStrata.push(...valueSteps); + // } + // + // const maxBarsPerLabel = Math.max( + // ...dataLabels.map((label) => label.values.length), + // ); + // + // return ( + //
+ // {(title || subTitle) && ( + //
+ // {title && + // React.createElement(titleType, { className: styles.title }, title)} + // {subTitle && + // React.createElement( + // subTitleType, + // { className: styles.subTitle }, + // subTitle, + // )} + // + //
+ //
+ //
+ //
+ //
+ // )} + // + //
+ // {showLegend && ( + //
+ // {dataSeries.map((series) => ( + //
+ //
+ //
{series.index}
+ //
+ // ))} + //
+ // )} + // + //
+ //
+ // {valuesLabel && ( + //
+ //
+ //
{valuesLabel}
+ //
+ //
+ // {verticalAxisStrata.map((value) => ( + //
+ // {formatValue(value, valuesFormat)} + //
+ // ))} + //
+ //
+ // )} + // + //
+ // {dataLabels.map((label) => ( + //
+ // {label.values.map((value) => ( + //
+ // ))} + //
+ // ))} + //
+ //
+ // + //
+ // {dataLabels.map((label) => ( + //
+ // {label.label} + //
+ // ))} + //
+ //
+ // + // {groupsLabel && ( + //
+ //
{groupsLabel}
+ //
+ // )} + //
+ //
+ // ); +}; + +export default NeuralMagicBar; diff --git a/src/components/graphs/data.jsx b/src/components/graphs/data.jsx new file mode 100644 index 00000000000..2f65ec246ae --- /dev/null +++ b/src/components/graphs/data.jsx @@ -0,0 +1,90 @@ +const dataSamples = { + bar: { + sample: [ + { index: "FP16 Baseline", label: "Dense", value: 14.9 }, + { index: "INT8 Weights & Activations", label: "Dense", value: 6.7 }, + { + index: "INT8 Weights & Activations", + label: "50% Sparsity", + value: 5.1, + }, + { + index: "INT8 Weights & Activations", + label: "70% Sparsity", + value: 3.9, + }, + { index: "INT4 Weights", label: "Dense", value: 5.1 }, + ], + }, + line: { + sample: [ + { index: "FP16 Baseline", label: 5.6, value: 14.9 }, + { index: "INT8 Weights & Activations", label: 10.3, value: 6.7 }, + { index: "INT8 Weights & Activations", label: 8.7, value: 5.1 }, + { index: "INT8 Weights & Activations", label: 3.2, value: 3.9 }, + { index: "INT4 Weights", label: 2.1, value: 5.1 }, + ], + }, +}; + +const formatData = ({ data, indexColors, colorShift = 0 }) => { + const indices = []; + const labels = []; + let colorIndex = 0; + + for (const { value, label, index = null } of data) { + let dataSeries = indices.find((series) => series.index === index); + if (!dataSeries) { + dataSeries = { + index, + color: indexColors[(colorIndex + colorShift) % indexColors.length], + data: [], + }; + indices.push(dataSeries); + colorIndex += 1; + } + dataSeries.data.push({ index, label, value, color: dataSeries.color }); + + let dataLabel = labels.find((dataLabel) => dataLabel.label === label); + if (!dataLabel) { + dataLabel = { label, data: [] }; + labels.push(dataLabel); + } + dataLabel.data.push({ index, label, value, color: dataSeries.color }); + } + + return { + data, + indices, + labels, + }; +}; + +const extractData = ({ + data, + children, + file, + testDataType, + chartType, + indexColors, + colorShift, +}) => { + // format the data to use + let extracted = data; + + if (children) { + throw new Error("Children are not supported for this component."); + } + + if (file) { + throw new Error("File is not supported for this component."); + } + + if (testDataType) { + extracted = dataSamples[chartType][testDataType]; + } + + return formatData({ data: extracted, indexColors, colorShift }); +}; + +export { dataSamples, formatData, extractData }; diff --git a/src/components/graphs/graphs.svg.jsx b/src/components/graphs/graphs.svg.jsx new file mode 100644 index 00000000000..2b385b84e66 --- /dev/null +++ b/src/components/graphs/graphs.svg.jsx @@ -0,0 +1,765 @@ +import { createText, pointsToPathD } from "./svg"; +import { Point, Rectangle } from "./vector"; +import { hashObjects, stringFormat, textDimensions } from "./utilities"; + +const createBackground = ({ + width, + height, + bottomHeading, + headingMargin = 0, + cornerRadius = 16, + color = "white", + borderColor = "white", + borderWidth = 0, + stylePulltab = false, + pullTabGap = 12, + pullTabInset = 32, +}) => { + const key = hashObjects({ + width, + height, + bottomHeading, + cornerRadius, + color, + borderColor, + borderWidth, + stylePulltab, + pullTabGap, + pullTabInset, + }); + + if (!stylePulltab) { + const backgroundRect = ( + + ); + + return { + elements: [backgroundRect], + dimensions: new Rectangle(0, 0, width, height), + graphTop: bottomHeading + headingMargin, + }; + } + + const pullTabMeasurements = { + top: 0, + bottom: bottomHeading + headingMargin, + left: 0, + leftInset: pullTabInset, + right: width, + rightInset: width - pullTabInset, + }; + const graphRectMeasurements = { + top: bottomHeading + headingMargin + pullTabGap, + bottom: height, + left: 0, + right: width, + }; + + const backgroundPath = ( + + ); + + return { + elements: [backgroundPath], + dimensions: new Rectangle(0, 0, width, height), + graphTop: graphRectMeasurements.top + headingMargin, + }; +}; + +const createGraphBackground = ({ + anchorPoint, + width, + height, + color = "white", + cornerRadius = 16, + borderColor = "white", + borderWidth = 0, + verticalAxisSide = "", // "start" or "end" (left or right) + horizontalAxisSide = "", // "start" or "end" (top or bottom) +}) => { + const cornersRadii = [ + verticalAxisSide !== "start" && horizontalAxisSide !== "start" + ? cornerRadius + : 0, // top left + verticalAxisSide !== "end" && horizontalAxisSide !== "start" + ? cornerRadius + : 0, // top right + verticalAxisSide !== "end" && horizontalAxisSide !== "end" + ? cornerRadius + : 0, // bottom right + verticalAxisSide !== "start" && horizontalAxisSide !== "end" + ? cornerRadius + : 0, // bottom left + ]; + const elements = [ + , + ]; + + return { + elements, + dimensions: new Rectangle(anchorPoint.x, anchorPoint.y, width, height), + }; +}; + +const createHeading = ({ + xPosition, + yPosition, + width, + align = "left", // "left", "center", "right" + title = null, + titleType = "h2", + titleColor = "black", + titlesSpacing = 8, + subTitle = null, + subTitleType = "h6", + subTitleColor = "grey", +}) => { + if (xPosition === null || xPosition === undefined) { + throw new Error("Invalid xPosition"); + } + + if (width === null || width === undefined) { + throw new Error("Invalid width"); + } + + if (yPosition === null || yPosition === undefined) { + throw new Error("Invalid yPosition"); + } + + if (["left", "center", "right"].indexOf(align) === -1) { + throw new Error(`Invalid align: ${align}`); + } + + const boundsStart = new Point(xPosition, yPosition); + const boundsEnd = new Point(xPosition + width, yPosition); + let textAnchor; + let textAlignment; + + if (align === "left") { + textAnchor = new Point(boundsStart.x, boundsStart.y); + textAlignment = "start"; + } else if (align === "center") { + textAnchor = new Point(boundsStart.x + width / 2, boundsStart.y); + textAlignment = "middle"; + } else if (align === "right") { + textAnchor = new Point(boundsEnd.x, boundsStart.y); + textAlignment = "end"; + } + + const elements = []; + + if (title) { + const titleText = createText({ + text: title, + style: titleType, + anchorPoint: textAnchor, + color: titleColor, + mainAlignment: textAlignment, + maxMainAxis: width, + }); + elements.push(...titleText.elements); + textAnchor.y += titleText.dimensions.height() + titlesSpacing; + boundsEnd.y += + titleText.dimensions.height() + (subTitle ? titlesSpacing : 0); + } + + if (subTitle) { + const subTitleText = createText({ + text: subTitle, + style: subTitleType, + anchorPoint: textAnchor, + color: subTitleColor, + mainAlignment: textAlignment, + maxMainAxis: width, + }); + elements.push(...subTitleText.elements); + boundsEnd.y += subTitleText.dimensions.height(); + } + + return { + elements, + dimensions: new Rectangle( + boundsStart.x, + boundsStart.y, + boundsEnd.x - boundsStart.x, + boundsEnd.y - boundsStart.y, + ), + }; +}; + +const createLegend = ({ + series = [], + xPosition, + yPosition, + width, + align = "center", + colorSquareSize = 16, + gap = 16, + labelMargin = 8, + textType = "body1", + textColor = "grey", +}) => { + if (xPosition === null || xPosition === undefined) { + throw new Error("Invalid xPosition"); + } + + if (width === null || width === undefined) { + throw new Error("Invalid width"); + } + + if (yPosition === null || yPosition === undefined) { + throw new Error("Invalid yPosition"); + } + + if (["left", "center", "right"].indexOf(align) === -1) { + throw new Error(`Invalid align: ${align}`); + } + + const key = hashObjects({ + series, + xPosition, + yPosition, + width, + align, + colorSquareSize, + gap, + textType, + textColor, + }); + + // figure out the dimensions of each series and map them into rows + const seriesDimensionsByRow = [ + { + width: 0, + height: 0, + values: [], + }, + ]; + let currentRow = 0; + series.forEach((series) => { + const remainingRowWidth = + width - + seriesDimensionsByRow[currentRow].width - + (seriesDimensionsByRow[currentRow].values.length > 0 ? gap : 0); + const seriesTextDimensions = textDimensions(series.index, textType); + const seriesWidth = + colorSquareSize + labelMargin + seriesTextDimensions.width; + + if (seriesWidth <= remainingRowWidth) { + seriesDimensionsByRow[currentRow].width += + seriesWidth + + (seriesDimensionsByRow[currentRow].values.length > 0 ? gap : 0); + seriesDimensionsByRow[currentRow].height = Math.max( + seriesDimensionsByRow[currentRow].height, + seriesTextDimensions.height, + colorSquareSize, + ); + seriesDimensionsByRow[currentRow].values.push(series); + } else { + seriesDimensionsByRow.push({ + width: seriesWidth <= width ? seriesWidth : width, + height: Math.max(seriesTextDimensions.height, colorSquareSize), + values: [series], + }); + currentRow += 1; + } + }); + + // now create the SVG elements by row based on alignment + const elements = []; + let currentY = yPosition; + + seriesDimensionsByRow.forEach((row, rowIndex) => { + let rowLeftX = + align === "left" + ? xPosition + : align === "center" + ? xPosition + (width - row.width) / 2 + : xPosition + width - row.width; + let rowCenterY = currentY + row.height / 2; + + row.values.forEach((series, seriesIndex) => { + // create the SVG elements for the series: [color square - gap - text] + + const squareYStart = rowCenterY - colorSquareSize / 2; + const colorSquare = ( + + ); + elements.push(colorSquare); + rowLeftX += colorSquareSize + labelMargin; + + // get the height of the rendered text first + const tmpSeriesText = createText({ + text: series.index, + style: textType, + anchorPoint: new Point(0, 0), + maxMainAxis: width - rowLeftX, + }); + const seriesText = createText({ + text: series.index, + style: textType, + anchorPoint: new Point(rowLeftX, currentY), + color: textColor, + maxMainAxis: width - rowLeftX, + }); + + elements.push(...seriesText.elements); + rowLeftX += seriesText.dimensions.width() + gap; + }); + + currentY += row.height + labelMargin; + }); + + currentY -= labelMargin; // remove the last spacing + + return { + elements, + dimensions: new Rectangle( + xPosition, + yPosition, + width, + currentY - yPosition, + ), + }; +}; + +const createVerticalAxis = ({ + xPosition, + yPosition, + height, + steps = null, + stepsMargin = 8, + format = null, + label = null, + labelType = "body1", + labelColor = "grey", + labelMargin = 8, +}) => { + if (xPosition === null || xPosition === undefined) { + throw new Error("Invalid xPosition"); + } + + if (height === null || height === undefined) { + throw new Error("Invalid width"); + } + + if (yPosition === null || yPosition === undefined) { + throw new Error("Invalid yPosition"); + } + + const key = hashObjects({ + xPosition, + yPosition, + height, + steps, + stepsMargin, + format, + label, + labelType, + labelColor, + labelMargin, + }); + const elements = []; + const boundsStart = new Point(xPosition, yPosition); + const boundsEnd = new Point(xPosition, yPosition + height); + + // create the label, if it exists + if (label) { + const labelText = createText({ + text: label, + style: labelType, + anchorPoint: new Point(xPosition, yPosition + height / 2), + color: labelColor, + mainAlignment: "middle", + maxMainAxis: height, + rotation: 270, + }); + elements.push(...labelText.elements); + boundsEnd.x += labelText.dimensions.width() + labelMargin; + elements.push(( + + )) + } + + // create the steps, if they exist + if (steps) { + // calculate anchors for each step + // index 0 is top aligned, last index is bottom aligned, all others are equally spaced and centered + const stepsSpacing = height / (steps.length - 1); + const stepsX = xPosition + stepsMargin; + + steps.forEach((step, index) => { + let anchorPoint; + let secondaryAlignment; + + if (index === 0) { + anchorPoint = new Point(stepsX, yPosition + height); + secondaryAlignment = "end"; + } else if (index === steps.length - 1) { + anchorPoint = new Point(stepsX, yPosition); + secondaryAlignment = "start"; + } else { + anchorPoint = new Point(stepsX, (yPosition + height) - stepsSpacing * index); + secondaryAlignment = "middle"; + } + + const stepText = createText({ + text: format ? stringFormat(step, format) : step, + style: labelType, + anchorPoint, + color: labelColor, + mainAlignment: "start", + secondaryAlignment, + maxMainAxis: stepsSpacing / 2, + }); + elements.push(...stepText.elements); + + const stepRight = stepText.dimensions.x + stepText.dimensions.width(); + boundsEnd.x = Math.max(boundsEnd.x, stepRight); + }); + } + + const debugRect = ( + + ); + elements.push(debugRect); + + return { + elements, + dimensions: new Rectangle( + boundsStart.x, + boundsStart.y, + boundsEnd.x - boundsStart.x, + boundsEnd.y - boundsStart.y, + ), + }; + + // // determine all dimensions needed + // let labelBounds = new Rectangle(0, 0, 0, height); + // let stepsContainerBounds = new Rectangle(0, 0, 0, height); + // const stepBounds = []; + // + // if (label) { + // const { bounds } = createText({ + // text: label, + // style: labelType, + // anchorPoint: new Point(0, 0), + // color: labelColor, + // maxMainAxis: height, + // orientation: "vertical", + // mainAlignment: "middle", + // }); + // labelBounds = new Rectangle(0, 0, bounds.width, height); + // } + // + // if (steps) { + // const maxStepWidth = steps + // .map((step) => { + // const { bounds } = createText({ + // text: format ? stringFormat(step, format) : step, + // style: labelType, + // anchorPoint: new Point(0, 0), + // color: labelColor, + // }); + // stepBounds.push(bounds); + // + // return bounds.width; + // }) + // .reduce((a, b) => Math.max(a, b), 0); + // stepsContainerBounds = new Rectangle(0, 0, maxStepWidth, height); + // } + // + // const elements = []; + // const totalStepsHeight = stepBounds + // .map((bounds) => bounds.height) + // .reduce((a, b) => a + b, 0); + // const middleStepsHeight = + // totalStepsHeight - + // stepBounds[0].height - + // stepBounds[stepBounds.length - 1].height; + // const middleStepsPadding = (height - totalStepsHeight) / (steps.length - 1); + // let currentX = anchorPoint.x; + // + // if (position === "left") { + // // create the label, if it exists + // if (label) { + // const { svgText, height } = createText({ + // text: label, + // style: labelType, + // anchorPoint: new Point(currentX, anchorPoint.y), + // color: labelColor, + // maxMainAxis: height, + // orientation: "vertical", + // }); + // elements.push(svgText); + // currentX += labelBounds.width + labelPadding; + // } + // + // // create the steps, if they exist + // let currentY = anchorPoint.y; + // + // if (steps) { + // for (let i = 0; i < steps.length; i++) { + // const { svgText, height } = createText({ + // text: format ? stringFormat(steps[i], format) : steps[i], + // style: labelType, + // anchorPoint: new Point(currentX, currentY), + // color: labelColor, + // }); + // elements.push(svgText); + // currentY += height + (i === 0 ? middleStepsPadding : 0); + // } + // + // currentX += stepsContainerBounds.width + stepsPadding; + // } + // } else if (position === "right") { + // let currentY = anchorPoint.y; + // + // // on the right side, create the steps first + // if (steps) { + // currentX += stepsPadding; + // + // for (let i = 0; i < steps.length; i++) { + // const { svgText, height } = createText({ + // text: format ? stringFormat(steps[i], format) : steps[i], + // style: labelType, + // anchorPoint: new Point(currentX, currentY), + // color: labelColor, + // }); + // elements.push(svgText); + // currentY += height + (i === 0 ? middleStepsPadding : 0); + // } + // } + // + // // create the label, if it exists + // if (label) { + // currentX += labelPadding; + // + // const { svgText, height } = createText({ + // text: label, + // style: labelType, + // anchorPoint: new Point(currentX, anchorPoint.y), + // color: labelColor, + // maxMainAxis: height, + // orientation: "vertical_180", + // }); + // elements.push(svgText); + // } + // } + // + // return { + // elements, + // dimensions: new Rectangle( + // anchorPoint.x, + // anchorPoint.y, + // currentX - anchorPoint.x, + // height, + // ), + // }; +}; + +const createHorizontalAxis = ({ + xPosition, + yPosition, + width, + steps = null, + stepsMargin = 8, + format = null, + label = null, + labelType = "body1", + labelColor = "grey", + labelMargin = 8, +}) => { + if (xPosition === null || xPosition === undefined) { + throw new Error("Invalid xPosition"); + } + + if (width === null || width === undefined) { + throw new Error("Invalid width"); + } + + if (yPosition === null || yPosition === undefined) { + throw new Error("Invalid yPosition"); + } + + const key = hashObjects({ + xPosition, + yPosition, + width, + steps, + stepsMargin, + format, + label, + labelType, + labelColor, + labelMargin, + }); + const elements = []; + const boundsStart = new Point(xPosition, yPosition); + const boundsEnd = new Point(xPosition + width, yPosition); + + // create the steps, if they exist + if (steps) { + // calculate anchors for each step + // index 0 is left aligned, last index is right aligned, all others are equally spaced and centered + const stepsSpacing = width / (steps.length - 1); + const stepsY = yPosition + stepsMargin; + + steps.forEach((step, index) => { + let anchorPoint; + let mainAlignment; + + if (index === 0) { + anchorPoint = new Point(xPosition, stepsY); + mainAlignment = "start"; + } else if (index === steps.length - 1) { + anchorPoint = new Point(xPosition + width, stepsY); + mainAlignment = "end"; + } else { + anchorPoint = new Point(xPosition + stepsSpacing * index, stepsY); + mainAlignment = "middle"; + } + + const stepText = createText({ + text: format ? stringFormat(step, format) : step, + style: labelType, + anchorPoint, + color: labelColor, + mainAlignment, + maxMainAxis: stepsSpacing / 2, + }); + elements.push(...stepText.elements); + + const stepBottom = stepText.dimensions.y + stepText.dimensions.height(); + boundsEnd.y = Math.max(boundsEnd.y, stepBottom); + }); + } + + // create the label if it exists + if (label) { + const labelText = createText({ + text: label, + style: labelType, + anchorPoint: new Point(xPosition + width / 2, boundsEnd.y + labelMargin), + color: labelColor, + mainAlignment: "middle", + maxMainAxis: width, + }); + elements.push(...labelText.elements); + boundsEnd.y += labelText.dimensions.height() + labelMargin; + } + + return { + elements, + dimensions: new Rectangle( + boundsStart.x, + boundsStart.y, + boundsEnd.x - boundsStart.x, + boundsEnd.y - boundsStart.y, + ), + }; +}; + +export { + createBackground, + createGraphBackground, + createHeading, + createLegend, + createVerticalAxis, + createHorizontalAxis, +}; diff --git a/src/components/graphs/line/index.jsx b/src/components/graphs/line/index.jsx new file mode 100644 index 00000000000..c39d3b77c62 --- /dev/null +++ b/src/components/graphs/line/index.jsx @@ -0,0 +1,500 @@ +import React from "react"; + +import { Point, Line, Triangle, Polygon, Rectangle } from "../vector"; +import { pointsToPathD, lineToPathD, createText, stringFormat } from "../svg"; +import { + createHeading, + createLegend, + createVerticalAxis, + createHorizontalAxis, + createBackground, + createGraphBackground, +} from "../graphs.svg"; +import { extractData } from "../data"; +import theme from "../theme"; +import { splitText } from "../utilities"; + +const createLineGraph = ({ + series, + verticalAxisBounds, + horizontalAxisBounds, + anchorPoint, + width, + height, + lineStrokeWidth = 4, + pointRadius = 8, +}) => { + const bounds = new Rectangle(anchorPoint.x, anchorPoint.y, width, height); + const elements = []; + + // convert each series data into markers for each point and lines between each point + series.forEach((series, seriesIndex) => { + const color = series.color; + const lines = []; + const markers = []; + let previousPoint = null; + + series.values.forEach(({ value, label }, index) => { + const percentX = + (value - horizontalAxisBounds.min) / + (horizontalAxisBounds.max - horizontalAxisBounds.min); + const percentY = + (value - verticalAxisBounds.min) / + (verticalAxisBounds.max - verticalAxisBounds.min); + const point = new Point( + anchorPoint.x + width * percentX, + anchorPoint.y + height * percentY, + ); + + if (previousPoint && lineStrokeWidth && lineStrokeWidth > 0) { + lines.push( + , + ); + } + + if (pointRadius && pointRadius > 0) { + markers.push( + , + ); + } + }); + + elements.push(...lines); + elements.push(...markers); + }); + + return { + elements, + dimensions: bounds, + }; +}; + +const NeuralMagicLineChart = ({ + // data + children, + file, + data, + testDataType = null, + + // general graph properties + width = 560, + height = 480, + chartStyle = "rectangular", + chartColorScheme = "light", + textScale = "normal", + seriesColorShift = 0, + markersSize = 8, + linesSize = 4, + + // heading properties + alignHeading = "left", + title = null, + subTitle = null, + + // legend properties + enableLegend = true, + legendAlign = "center", + + // x axis properties + showXAxis = true, + xAxisLabel = "Test X Axis Label", + xAxisValues = null, + xAxisValuesTotalSteps = 4, + xAxisValuesFormat = "#.#", + + // y axis properties + showYAxis = true, + yAxisLabel = "Test Y Axis Label", + yAxisValues = null, + yAxisValuesTotalSteps = 4, + yAxisValuesFormat = "#.#", +}) => { + // get the data + const extracted = extractData({ + data, + children, + file, + testDataType, + chartType: "line", + indexColors: theme.colors.data.series, + colorShift: seriesColorShift, + }); + if (!xAxisValues || xAxisValues.length === 0 || xAxisValues.length < 3) { + let min = + xAxisValues && xAxisValues.length > 0 + ? xAxisValues[0] + : Math.min(extracted.data.map((item) => item.label)); + let max = + xAxisValues && xAxisValues.length > 1 + ? xAxisValues[1] + : Math.max(extracted.data.map((item) => item.label)); + let distance = max - min; + min = min - distance * 0.1; + max = max + distance * 0.1; + const stepDistance = (max - min) / xAxisValuesTotalSteps; + xAxisValues = []; + for (let i = 0; i <= xAxisValuesTotalSteps; i++) { + xAxisValues.push(min + stepDistance * i); + } + } + if (!yAxisValues || yAxisValues.length === 0 || yAxisValues.length < 3) { + let min = + yAxisValues && yAxisValues.length > 0 + ? yAxisValues[0] + : Math.min(extracted.data.map((item) => item.value)); + let max = + yAxisValues && yAxisValues.length > 1 + ? yAxisValues[1] + : Math.max(extracted.data.map((item) => item.value)); + let distance = max - min; + min = min - distance * 0.1; + max = max + distance * 0.1; + const stepDistance = (max - min) / yAxisValuesTotalSteps; + yAxisValues = []; + for (let i = 0; i <= yAxisValuesTotalSteps; i++) { + yAxisValues.push(min + stepDistance * i); + } + } + + // start creating the graph + const layeredElements = { + backgrounds: [], + headings: [], + legends: [], + axis: [], + graphs: [], + }; + const currentPoint = new Point( + theme.styles.spacing.outerPadding, + theme.styles.spacing.outerPadding, + ); + + // create the heading first to enable background creation for the pull tab setup + const heading = createHeading({ + xPosition: currentPoint.x, + width: width - 2 * theme.styles.spacing.outerPadding, + yPosition: currentPoint.y, + align: alignHeading, + title, + titleType: theme.styles.font.sizes[textScale].title, + titleColor: theme.functions.chartSchemeColor( + chartColorScheme, + "textPrimary", + ), + titlesSpacing: theme.styles.spacing.titleSubTitleMargin, + subTitle, + subTitleType: theme.styles.font.sizes[textScale].subTitle, + subTitleColor: theme.functions.chartSchemeColor( + chartColorScheme, + "textSecondary", + ), + }); + layeredElements.headings.push(...heading.elements); + currentPoint.y = heading.dimensions.y + heading.dimensions.height(); + + // create the background next (needs the heading height) to figure out where the graph will fit + const background = createBackground({ + width, + height, + bottomHeading: currentPoint.y, + headingMargin: theme.styles.spacing.headingMargin, + color: theme.functions.chartSchemeColor(chartColorScheme, "background"), + borderColor: theme.functions.chartSchemeColor(chartColorScheme, "border"), + borderWidth: 1, + stylePulltab: chartStyle === "pulltab", + }); + layeredElements.backgrounds.push(...background.elements); + currentPoint.y = background.graphTop; + + // start creating the graph + + // create the legend first, legend is always above the graph if included + let legend = null; + + if (enableLegend) { + legend = createLegend({ + series: extracted.indices, + xPosition: currentPoint.x, + yPosition: currentPoint.y, + width: width - 2 * theme.styles.spacing.outerPadding, + align: "center", + gap: 16, + textType: theme.styles.font.sizes[textScale].axisLabels, + textColor: + chartColorScheme === "light" || chartColorScheme === "grey" + ? theme.colors.font.colors.light.primary + : theme.colors.font.colors.dark.primary, + }); + layeredElements.legends.push(...legend.elements); + currentPoint.y = legend.dimensions.y + legend.dimensions.height(); + } + + // determine the height of the horizontal axis to subtract from vertical axis and graph to fit everything + let horizontalAxisProjectedHeight = 0; + if (showXAxis) { + const tmpHorizontal = createHorizontalAxis({ + xPosition: currentPoint.x, + yPosition: currentPoint.y, + width: width - theme.styles.spacing.outerPadding * 2, + steps: xAxisValues, + stepsMargin: 8, + format: xAxisValuesFormat, + label: xAxisLabel, + labelType: theme.styles.font.sizes[textScale].axisLabels, + labelColor: + chartColorScheme === "light" || chartColorScheme === "grey" + ? theme.colors.font.colors.light.secondary + : theme.colors.font.colors.dark.secondary, + labelMargin: 8, + }); + horizontalAxisProjectedHeight = tmpHorizontal.dimensions.height(); + } + + const graphHeight = + height - + currentPoint.y - + theme.styles.spacing.outerPadding - + horizontalAxisProjectedHeight; + + // create the vertical axis + if (showYAxis) { + const verticalAxis = createVerticalAxis({ + xPosition: currentPoint.x, + yPosition: currentPoint.y, + height: graphHeight, + steps: yAxisValues, + stepsMargin: 8, + format: yAxisValuesFormat, + label: yAxisLabel, + labelType: theme.styles.font.sizes[textScale].axisLabels, + labelColor: + chartColorScheme === "light" || chartColorScheme === "grey" + ? theme.colors.font.colors.light.secondary + : theme.colors.font.colors.dark.secondary, + labelMargin: 8, + }); + layeredElements.axis.push(...verticalAxis.elements); + currentPoint.x += verticalAxis.dimensions.width(); + } + + return ( + + {layeredElements.backgrounds} + {layeredElements.headings} + {layeredElements.legends} + {layeredElements.axis} + {layeredElements.graphs} + + ); +}; + +export default NeuralMagicLineChart; + +const func = () => { + // // create the legend + // let legend = null; + // + // if (enableLegend) { + // legend = createLegend({ + // series, + // anchorPoint: currentPoint, + // maxWidth: width - padding * 2, + // align: legendAlign, + // colorSquareSize: markersSize, + // gap: 8, + // textType: textStyleMappings[textScale].axisLabels, + // textColor: + // chartColorScheme === "light" || chartColorScheme === "grey" + // ? colors.lightTextPrimary + // : colors.darkTextPrimary, + // }); + // + // elements.legends.push(...legend.elements); + // currentPoint.y += legend.dimensions.height; + // } + // + // if (!yAxisValues) { + // const min = Math.min( + // ...series.map((series) => + // Math.min(...series.values.map((value) => value.value)), + // ), + // ); + // const max = Math.max( + // ...series.map((series) => + // Math.max(...series.values.map((value) => value.value)), + // ), + // ); + // const step = (max - min) / yAxisValuesTotalSteps; + // yAxisValues = Array.from( + // { length: yAxisValuesTotalSteps + 1 }, + // (_, i) => min + step * i, + // ); + // } else if (yAxisValues.length === 2) { + // const min = yAxisValues[0]; + // const max = yAxisValues[1]; + // const step = (max - min) / yAxisValuesTotalSteps; + // yAxisValues = Array.from( + // { length: yAxisValuesTotalSteps + 1 }, + // (_, i) => min + step * i, + // ); + // } + // + // if (!xAxisValues) { + // const min = Math.min( + // ...series.map((series) => + // Math.min(...series.values.map((value) => value.label)), + // ), + // ); + // const max = Math.max( + // ...series.map((series) => + // Math.max(...series.values.map((value) => value.label)), + // ), + // ); + // const step = (max - min) / xAxisValuesTotalSteps; + // xAxisValues = Array.from( + // { length: xAxisValuesTotalSteps + 1 }, + // (_, i) => min + step * i, + // ); + // } else if (xAxisValues.length === 2) { + // const min = xAxisValues[0]; + // const max = xAxisValues[1]; + // const step = (max - min) / xAxisValuesTotalSteps; + // xAxisValues = Array.from( + // { length: xAxisValuesTotalSteps + 1 }, + // (_, i) => min + step * i, + // ); + // } + // + // // check the height of the horizontal axis to subtract from vertical axis and graph to fit everything + // let horizontalAxisProjectedHeight = 0; + // + // if (showXAxis) { + // const tmpHorizontal = createHorizontalAxis({ + // anchorPoint: currentPoint, + // width: width - padding * 2, + // steps: xAxisValues, + // stepsPadding: 8, + // format: xAxisValuesFormat, + // position: "bottom", + // label: xAxisLabel, + // labelType: textStyleMappings[textScale].axisLabels, + // labelColor: + // chartColorScheme === "light" || chartColorScheme === "grey" + // ? colors.lightTextSecondary + // : colors.darkTextSecondary, + // labelPadding: 8, + // }); + // horizontalAxisProjectedHeight = tmpHorizontal.dimensions.height; + // } + // + // // create the vertical axis + // if (showYAxis) { + // const verticalAxis = createVerticalAxis({ + // anchorPoint: currentPoint, + // height: height - currentPoint.y - padding - horizontalAxisProjectedHeight, + // steps: yAxisValues, + // stepsPadding: 8, + // format: yAxisValuesFormat, + // position: "left", + // label: yAxisLabel, + // labelType: textStyleMappings[textScale].axisLabels, + // labelColor: + // chartColorScheme === "light" || chartColorScheme === "grey" + // ? colors.lightTextSecondary + // : colors.darkTextSecondary, + // labelPadding: 8, + // }); + // elements.axis.push(...verticalAxis.elements); + // currentPoint.x += verticalAxis.dimensions.width; + // } + // + // // create the graph + // const graph = createLineGraph({ + // series, + // verticalAxisBounds: { + // min: yAxisValues[0], + // max: yAxisValues[yAxisValues.length - 1], + // }, + // horizontalAxisBounds: { + // min: xAxisValues[0], + // max: xAxisValues[xAxisValues.length - 1], + // }, + // anchorPoint: currentPoint, + // width: width - currentPoint.x - padding, + // height: height - currentPoint.y - padding - horizontalAxisProjectedHeight, + // lineStrokeWidth: linesSize, + // pointRadius: markersSize, + // }); + // elements.graphs.push(...graph.elements); + // currentPoint.y += graph.dimensions.height; + // + // // create the horizontal axis + // if (showXAxis) { + // const horizontalAxis = createHorizontalAxis({ + // anchorPoint: currentPoint, + // width: width - currentPoint.x - padding, + // steps: xAxisValues, + // stepsPadding: 8, + // format: xAxisValuesFormat, + // position: "bottom", + // label: xAxisLabel, + // labelType: textStyleMappings[textScale].axisLabels, + // labelColor: + // chartColorScheme === "light" || chartColorScheme === "grey" + // ? colors.lightTextSecondary + // : colors.darkTextSecondary, + // labelPadding: 8, + // }); + // elements.axis.push(...horizontalAxis.elements); + // currentPoint.y += horizontalAxis.dimensions.height; + // } + // + // // create the background + // const background = createBackground({ + // width, + // height, + // headingHeight: heading.dimensions.height, + // cornerRadius: 16, + // color: + // chartColorScheme === "light" + // ? colors.lightBackground + // : chartColorScheme === "grey" + // ? colors.greyBackground + // : colors.darkBackground, + // borderColor: + // chartColorScheme === "light" + // ? colors.lightBorder + // : chartColorScheme === "grey" + // ? colors.greyBorder + // : colors.darkBorder, + // borderWidth: 1, + // stylePulltab: chartStyle === "pulltab", + // pullTabGap: 16, + // pullTabInset: 48, + // }); + // elements.backgrounds.push(background); + // const graphBackground = createGraphBackground({ + // anchorPoint: graph.dimensions.points[0], + // width: graph.dimensions.width(), + // height: graph.dimensions.height(), + // color: + // chartColorScheme === "light" + // ? colors.lightGraphBackground + // : chartColorScheme === "grey" + // ? colors.greyGraphBackground + // : colors.darkGraphBackground, + // cornerRadius: 16, + // borderColor: + // chartColorScheme === "light" + // ? colors.lightBorder + // : chartColorScheme === "grey" + // ? colors.greyBorder + // : colors.darkBorder, + // borderWidth: 1, + // verticalAxisSide: showYAxis ? "start" : "", + // horizontalAxisSide: showXAxis ? "end" : "", + // }); +}; diff --git a/src/components/graphs/neuralnet/index.jsx b/src/components/graphs/neuralnet/index.jsx new file mode 100644 index 00000000000..e93ec7802e8 --- /dev/null +++ b/src/components/graphs/neuralnet/index.jsx @@ -0,0 +1,263 @@ +import React from "react"; +import seedrandom from "seedrandom"; +import { Line, Point } from "../vector"; +import { lineToPathD } from "../svg"; +import theme from "../theme"; + +const sparseWeightsEmulator = (layers, sparsity, layerVariance, seed) => { + console.log("sparseWeightsEmulator"); + const random = seedrandom(seed); + const layersWeights = []; + console.log(layers); + + for (let layerIndex = 0; layerIndex < layers.length - 1; layerIndex++) { + layersWeights.push([]); + const sourceActivations = layers[layerIndex]; + const targetActivations = layers[layerIndex + 1]; + const totalWeights = sourceActivations * targetActivations; + const minDenseWeights = (1 - (sparsity + layerVariance)) * totalWeights; + + // create random weight values between 0 and 1 while setting the number of weights needed for minDensity to 2 + const weightValues = []; + let denseCount = 0; + + for (let i = 0; i < totalWeights; i++) { + if (denseCount < minDenseWeights) { + weightValues.push(2); + denseCount++; + } else { + weightValues.push(random()); + } + } + + // assign random weights from the list to the connections + for (let sourceIndex = 0; sourceIndex < sourceActivations; sourceIndex++) { + for ( + let targetIndex = 0; + targetIndex < targetActivations; + targetIndex++ + ) { + const randomIndex = Math.floor(random() * weightValues.length); + const weight = weightValues.splice(randomIndex, 1)[0]; + layersWeights[layerIndex].push(weight); + } + } + } + + // now set the weights to sparse or dense based on their values while hitting the global sparsity target + const weightValues = layersWeights.flat(); + weightValues.sort(); + const sparsityIndex = Math.floor(weightValues.length * sparsity); + const denseThreshold = weightValues[sparsityIndex]; + + for (let layerIndex = 0; layerIndex < layersWeights.length; layerIndex++) { + for ( + let weightIndex = 0; + weightIndex < layersWeights[layerIndex].length; + weightIndex++ + ) { + layersWeights[layerIndex][weightIndex] = + layersWeights[layerIndex][weightIndex] < denseThreshold; + } + } + + return layersWeights; +}; + +const NeuralMagicNeuralNet = ({ + layers = [3, 4, 4, 2], + activationSize = 96, + weightSize = 20, + activationSpacing = 64, + activationStrokeWidth = 4, + layerSpacing = null, + colorIndex = 3, + sparsity = 0.7, + sparsityRandomSeed = 9, + weightCompression = 4, + activationCompression = 2, +}) => { + // if (!activationSpacing) { + // activationSpacing = activationSize * 0.5; + // } + // + // if (!layerSpacing) { + // layerSpacing = activationSpacing; + // } + // + // const maxLayerSize = Math.max(...layers); + // const layerCount = layers.length; + // const activationRadius = activationSize / 2; + // const quantizedActivationRadius = activationRadius / activationCompression; + // const weightWidth = weightSize; + // const quantizedWeightWidth = weightSize / weightCompression; + // + // const totalHeight = + // maxLayerSize * activationSize + + // (maxLayerSize - 1) * activationSpacing + + // 2 * activationStrokeWidth; + // const totalWidth = + // layerCount * activationSize + + // (layerCount - 1) * layerSpacing + + // 2 * activationStrokeWidth; + // + // const layersActivations = []; + // + // for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) { + // const activations = []; + // const layerSize = layers[layerIndex]; + // const layerWidth = activationSize + 2 * activationStrokeWidth; + // const layerHeight = + // layerSize * activationSize + (layerSize - 1) * activationSpacing; + // const layerX = + // layerIndex * (activationSize + layerSpacing) + activationStrokeWidth; + // const layerY = (totalHeight - layerHeight) / 2; + // + // for (let nodeIndex = 0; nodeIndex < layerSize; nodeIndex++) { + // const centerX = layerX + activationRadius; + // const centerY = + // layerY + + // activationRadius + + // nodeIndex * (activationSize + activationSpacing); + // activations.push({ + // base: new Point(centerX, centerY), + // quantized: activationCompression > 1, + // }); + // } + // + // layersActivations.push(activations); + // } + // + // const activationsList = layersActivations.flat(); + // const weights = []; + // const sparseWeights = sparseWeightsEmulator( + // layers, + // sparsity, + // 0, + // sparsityRandomSeed, + // ); + // + // for (let layerIndex = 0; layerIndex < layers.length - 1; layerIndex++) { + // const sourceLayer = layersActivations[layerIndex]; + // const targetLayer = layersActivations[layerIndex + 1]; + // + // for ( + // let sourceNodeIndex = 0; + // sourceNodeIndex < sourceLayer.length; + // sourceNodeIndex++ + // ) { + // const source = sourceLayer[sourceNodeIndex].base; + // + // for ( + // let targetNodeIndex = 0; + // targetNodeIndex < targetLayer.length; + // targetNodeIndex++ + // ) { + // const target = targetLayer[targetNodeIndex].base; + // const weight = { + // base: new Line( + // new Point(source.x, source.y), + // new Point(target.x, target.y), + // ), + // quantized: weightCompression > 1, + // sparse: + // sparsity > 0 && + // sparseWeights[layerIndex][ + // sourceNodeIndex * targetLayer.length + targetNodeIndex + // ], + // }; + // + // weights.push(weight); + // } + // } + // } + // + // const weightColor = "#848990"; + // const weightStrokeColor = colors.shadeColorHex(weightColor, -0.15); + // const sparseWeightColor = colors.setAlphaHex(weightColor, 0.25); + // const activationColor = colors.series[colorIndex % colors.series.length]; + // const uncompressedActivationColor = colors.setAlphaHex(activationColor, 0.25); + // const activationStrokeColor = colors.shadeColorHex( + // colors.series[colorIndex % colors.series.length], + // -0.15, + // ); + // + // return ( + // + // {weights.map((weight, index) => { + // // base weights + // return ( + // + // ); + // })} + // {weights.map((weight, index) => { + // // quantized weights + // if (weight.sparse || !weight.quantized) { + // return null; + // } + // + // return ( + // + // ); + // })} + // {activationsList.map((activation, layerIndex) => { + // return ( + // + // ); + // })} + // {activationsList.map((activation, layerIndex) => { + // // quantized activations + // if (!activation.quantized) { + // return null; + // } + // + // return ( + // + // ); + // })} + // + // ); +}; + +export default NeuralMagicNeuralNet; diff --git a/src/components/graphs/svg.jsx b/src/components/graphs/svg.jsx new file mode 100644 index 00000000000..2bee13cee97 --- /dev/null +++ b/src/components/graphs/svg.jsx @@ -0,0 +1,279 @@ +import { Point, Line, Rectangle } from "./vector"; +import theme from "./theme"; +import { atan2 } from "mathjs"; +import { hashObjects, splitText } from "./utilities"; + +function pointsToPathD({ points, cornerRadius = 0, closePath = true }) { + const cornerRadii = + typeof cornerRadius === "number" + ? new Array(points.length).fill(cornerRadius) + : cornerRadius; + + // First map the points to vertices taking into account any corner radius + // veretx format is {start: Point, control: Point, end: Point, hasCorner: boolean} + const vertices = []; + points.forEach((point, index) => { + const prevPoint = points[index - 1] || points[points.length - 1]; + const nextPoint = points[(index + 1) % points.length]; + const currentCornerRadius = cornerRadii[index]; + + if (!currentCornerRadius || currentCornerRadius < 1) { + vertices.push({ + start: point, + control: point, + end: point, + hasCorner: false, + }); + } else { + const startLine = new Line(prevPoint, point); + const endLine = new Line(point, nextPoint); + + vertices.push({ + start: startLine.pointAt( + (startLine.length() - currentCornerRadius) / startLine.length(), + ), + control: point, + end: endLine.pointAt(currentCornerRadius / endLine.length()), + hasCorner: true, + }); + } + }); + vertices.push(vertices[0]); + + // Now map the vertices to SVG path d attribute format + const d = []; + vertices.forEach((vertex, index) => { + if (index === 0) { + d.push(`M ${vertex.end.x},${vertex.end.y}`); + } else if (!vertex.hasCorner) { + d.push(`L ${vertex.control.x},${vertex.control.y}`); + } else { + d.push(`L ${vertex.start.x},${vertex.start.y}`); + d.push( + `Q ${vertex.control.x},${vertex.control.y} ${vertex.end.x},${vertex.end.y}`, + ); + } + }); + + if (closePath) { + d.push("Z"); + } + + return d.join(" "); +} + +function lineToPathD(line, thickness, closePath = true) { + const offset = thickness / 2; + let angle = + atan2(line.end.y - line.start.y, line.end.x - line.start.x) + Math.PI / 2; + + const offsetX = offset * Math.cos(angle); + const offsetY = offset * Math.sin(angle); + + const points = [ + new Point(line.start.x - offsetX, line.start.y - offsetY), + new Point(line.start.x + offsetX, line.start.y + offsetY), + new Point(line.end.x + offsetX, line.end.y + offsetY), + new Point(line.end.x - offsetX, line.end.y - offsetY), + new Point(line.start.x - offsetX, line.start.y - offsetY), + ]; + + let d = ""; + + points.forEach((point, index) => { + if (index === 0) { + d += `M ${point.x},${point.y}`; + } else { + d += ` L ${point.x},${point.y}`; + } + }); + + if (closePath) { + d += " Z"; + } + + return d; +} + +const validateTextInputs = ({ + text, + style, + anchorPoint, + mainAlignment, + secondaryAlignment, +}) => { + if (theme.styles.font.properties[style] === undefined) { + throw new Error(`Invalid style: ${style}`); + } + + if (["start", "middle", "end"].indexOf(mainAlignment) === -1) { + throw new Error(`Invalid mainAlignment: ${mainAlignment}`); + } + + if (["start", "middle", "end"].indexOf(secondaryAlignment) === -1) { + throw new Error(`Invalid secondaryAlignment: ${secondaryAlignment}`); + } + + if (text === null || text === undefined || text === "") { + return { + elements: null, + dimensions: new Rectangle(anchorPoint.x, anchorPoint.y, 0, 0), + }; + } + + return null; +}; + +const createText = ({ + text, + style, + anchorPoint, + color = "black", + mainAlignment = "start", + secondaryAlignment = "start", + maxMainAxis = null, + lineSpacing = 0.1, + rotation = 0, +}) => { + const nullResponse = validateTextInputs({ + text, + style, + anchorPoint, + mainAlignment, + secondaryAlignment, + }); + + if (nullResponse !== null) { + return nullResponse; + } + + const key = hashObjects([ + text, + style, + color, + mainAlignment, + maxMainAxis, + lineSpacing, + ]); + + // Split text into lines and determine dimensions + const { lines, dimensions } = splitText(text, maxMainAxis, style); + let maxLineHeight = Math.max(...dimensions.map((dim) => dim.height)); + let lineDeltaY = maxLineHeight * lineSpacing + maxLineHeight; + let maxLineWidth = Math.max(...dimensions.map((dim) => dim.width)); + let totalHeight = lineDeltaY * (lines.length - 1) + maxLineHeight; + + let textAnchorX; + let textAnchorY; + let boundAnchorX; + let boundAnchorY; + + if (mainAlignment === "start") { + textAnchorX = anchorPoint.x; + boundAnchorX = anchorPoint.x; + } else if (mainAlignment === "middle") { + textAnchorX = anchorPoint.x; + boundAnchorX = anchorPoint.x - maxLineWidth / 2; + } else if (mainAlignment === "end") { + textAnchorX = anchorPoint.x; + boundAnchorX = anchorPoint.x - maxLineWidth; + } + + if (secondaryAlignment === "start") { + textAnchorY = anchorPoint.y; + boundAnchorY = anchorPoint.y; + } else if (secondaryAlignment === "middle") { + textAnchorY = anchorPoint.y - totalHeight / 2; + boundAnchorY = anchorPoint.y - totalHeight / 2; + } else if (secondaryAlignment === "end") { + textAnchorY = anchorPoint.y - totalHeight; + boundAnchorY = anchorPoint.y - totalHeight; + } + + // Rotation calculations + const textLineSettings = []; + + if (rotation === 0) { + lines.forEach((line, index) => { + textLineSettings.push({ + line, + x: textAnchorX, + y: textAnchorY + index * lineDeltaY, + textAnchor: mainAlignment, + alignmentBaseline: "hanging", + transform: "", + }); + }); + } else if (rotation === 270) { + maxLineWidth = lineDeltaY * (lines.length - 1) + maxLineHeight; + totalHeight = Math.max(...dimensions.map((dim) => dim.width)); + + // Reorient the text lines with the given rotation while matching alignment to the original desired anchor + lines.forEach((line, index) => { + // first find rotated center point for each line + const orignalX = textAnchorX; + const originalY = textAnchorY + index * lineDeltaY; + const orignalDims = dimensions[index]; + + // now change out all text for center anchors and alignment for easy rotation and translation + let originalCenterX; + let originalCenterY; + + if (mainAlignment === "start") { + originalCenterX = orignalX + orignalDims.width / 2; + } else if (mainAlignment === "middle") { + originalCenterX = orignalX; + } else if (mainAlignment === "end") { + originalCenterX = orignalX - orignalDims.width / 2; + } + + if (secondaryAlignment === "start") { + originalCenterY = originalY; + } else if (secondaryAlignment === "middle") { + originalCenterY = originalY + orignalDims.height / 2; + } else if (secondaryAlignment === "end") { + originalCenterY = originalY + orignalDims.height; + } + + // convert into line settings and correct offsets + textLineSettings.push({ + line, + x: originalCenterX, + y: originalCenterY + orignalDims.height / 2 + index * lineDeltaY, + textAnchor: "middle", + alignmentBaseline: "middle", + transform: `rotate(${rotation} ${originalCenterX} ${originalCenterY})`, + }); + }); + } + + // Convert lines settings into SVG elements + const elements = textLineSettings.map((settings, index) => { + return ( + + {settings.line} + + ); + }); + + return { + elements, + dimensions: new Rectangle( + boundAnchorX, + boundAnchorY, + maxLineWidth, + totalHeight, + ), + }; +}; + +export { pointsToPathD, lineToPathD, createText }; diff --git a/src/components/graphs/theme.jsx b/src/components/graphs/theme.jsx new file mode 100644 index 00000000000..e1e0a89d887 --- /dev/null +++ b/src/components/graphs/theme.jsx @@ -0,0 +1,249 @@ +function decimalToHex(d, padding) { + let hex = Number(d).toString(16); + padding = + typeof padding === "undefined" || padding === null + ? (padding = 2) + : padding; + + while (hex.length < padding) { + hex = "0" + hex; + } + + return hex; +} + +const shadeColorHex = (color, percentage) => { + let colorString = color.replace("#", ""); + + if (colorString.length === 6) { + colorString += "FF"; + } + + let red = parseInt(colorString.substr(0, 2), 16); + let green = parseInt(colorString.substr(2, 2), 16); + let blue = parseInt(colorString.substr(4, 2), 16); + const alpha = parseInt(colorString.substr(6, 2), 16); + + if (percentage > 0) { + // lighten where 1 is full white, 0 is no change, and close to 0 is minimal change + red = Math.round(red + (255 - red) * percentage); + green = Math.round(green + (255 - green) * percentage); + blue = Math.round(blue + (255 - blue) * percentage); + } else { + // darken where 1 is full black, 0 is no change, and close to 0 is minimal change + red = Math.round(red - red * -1 * percentage); + green = Math.round(green - green * -1 * percentage); + blue = Math.round(blue - blue * -1 * percentage); + } + + console.log(`red: ${red}, green: ${green}, blue: ${blue}, alpha: ${alpha}`); + + return `#${decimalToHex(red)}${decimalToHex(green)}${decimalToHex(blue)}${decimalToHex(alpha)}`; +}; + +function setAlphaHex(color, opacity) { + let colorString = color.replace("#", ""); + + if (colorString.length > 6) { + colorString = colorString.substring(0, 6); + } + + const alpha = Math.round(Math.min(Math.max(opacity, 0), 1) * 255); + + return `#${colorString}${decimalToHex(alpha)}`; +} + +const fontFamily = "Space Grotesk, sans-serif"; +const textFontProperties = { + h1: { + fontFamily, + fontStyle: "normal", + fontWeight: "normal", + fontSize: "96px", + }, + h2: { + fontFamily, + fontStyle: "normal", + fontWeight: "normal", + fontSize: "60px", + }, + h3: { + fontFamily: "Spezia", + fontStyle: "normal", + fontWeight: "normal", + fontSize: "48px", + }, + h4: { + fontFamily, + fontStyle: "normal", + fontWeight: "normal", + fontSize: "32px", + }, + h5: { + fontFamily, + fontStyle: "normal", + fontWeight: "normal", + fontSize: "24px", + }, + h6: { + fontFamily, + fontStyle: "normal", + fontWeight: "normal", + fontSize: "20px", + }, + subtitle1: { + fontFamily: "Inter", + fontStyle: "normal", + fontWeight: "600", + fontSize: "22px", + }, + subtitle2: { + fontFamily: "Inter", + fontStyle: "normal", + fontWeight: "600", + fontSize: "16px", + }, + body1: { + fontFamily: "Inter", + fontStyle: "normal", + fontWeight: "normal", + fontSize: "18px", + }, + body2: { + fontFamily: "Inter", + fontStyle: "normal", + fontWeight: "normal", + fontSize: "16px", + }, + caption: { + fontFamily: "Inter", + fontStyle: "normal", + fontWeight: "normal", + fontSize: "12px", + }, +}; + +const colors = { + data: { + series: ["#2A8EFD", "#03C883", "#FFC93F", "#FF8228", "#FF2929"], + seriesFont: ["#FFFFFF", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#FFFFFF"], + }, + font: { + colors: { + light: { + primary: "#000000", + secondary: "#111111", + }, + dark: { + primary: "#FFFFFF", + secondary: "#EEEEEE", + }, + }, + }, + surfaces: { + light: { + background: "#FFFFFF", + border: "#E0E0E0", + graph: "#FFFFFF", + graphBorder: "#E0E0E0", + }, + grey: { + background: "#F4F5F9", + border: "#E0E0E0", + graph: "#F4F5F9", + graphBorder: "#E0E0E0", + }, + dark: { + background: "#000000", + border: "#000000", + graph: "#000000", + graphBorder: "#000000", + }, + }, +}; + +const styles = { + font: { + properties: textFontProperties, + sizes: { + small: { + title: "h5", + subTitle: "caption", + axisLabels: "body1", + axisTicks: "body2", + }, + normal: { + title: "h4", + subTitle: "body2", + axisLabels: "body1", + axisTicks: "body2", + }, + large: { + title: "h3", + subTitle: "body1", + axisLabels: "body1", + axisTicks: "body2", + }, + }, + }, + spacing: { + outerPadding: 24, + headingMargin: 24, + titleSubTitleMargin: 16, + }, +}; + +export default { + colors, + styles, + functions: { + hexShade: (index, percent) => shadeColorHex(series[index], percent), + hexAlpha: setAlphaHex, + decimalToHex, + chartSchemeColor: (scheme, type) => { + if (type === "text" || type === "textPrimary") { + return scheme === "light" || scheme === "grey" + ? colors.font.colors.light.primary + : colors.font.colors.dark.primary; + } + + if (type === "textSecondary") { + return scheme === "light" || scheme === "grey" + ? colors.font.colors.light.secondary + : colors.font.colors.dark.secondary; + } + + if (type === "background") { + return scheme === "light" + ? colors.surfaces.light.background + : scheme === "grey" + ? colors.surfaces.grey.background + : colors.surfaces.dark.background; + } + + if (type === "border") { + return scheme === "light" + ? colors.surfaces.light.border + : scheme === "grey" + ? colors.surfaces.grey.border + : colors.surfaces.dark.border; + } + + if (type === "graph") { + return scheme === "light" + ? colors.surfaces.light.graph + : scheme === "grey" + ? colors.surfaces.grey.graph + : colors.surfaces.dark.graph; + } + + if (type === "graphBorder") { + return scheme === "light" + ? colors.surfaces.light.graphBorder + : scheme === "grey" + ? colors.surfaces.grey.graphBorder + : colors.surfaces.dark.graphBorder; + } + }, + }, +}; diff --git a/src/components/graphs/tradeoff-triangle/index.jsx b/src/components/graphs/tradeoff-triangle/index.jsx new file mode 100644 index 00000000000..0ac3d60044c --- /dev/null +++ b/src/components/graphs/tradeoff-triangle/index.jsx @@ -0,0 +1,121 @@ +import React from "react"; + +import theme from "../theme"; +import { Point, Line, Triangle, Polygon } from "../vector"; +import { pointsToPathD, createText } from "../svg"; + +const NeuralMagicTradeoffTriangle = ({ + width = null, + height = 480, + spacing = 4, + colorsStartIndex = 2, + firstLabel = "Tradeoff One", + secondLabel = "Tradeoff Two", + thirdLabel = "Tradeoff Three", + labelSize = 32, +}) => { + // if (width && !height) { + // height = 0.5 * Math.sqrt(3) * width; + // } else if (!width && height) { + // width = 2 * (1 / Math.sqrt(3)) * height; + // } else if (!width && !height) { + // console.error( + // "Either height or width must be given for NeuralMagicTradeoffTriangle", + // ); + // return
; + // } + // + // const triangle = new Triangle( + // new Point(0, height), + // new Point(width / 2, 0), + // new Point(width, height), + // ); + // const tradeoffTop = new Polygon([ + // triangle.pointB.clone(), // Top of triangle + // triangle.edgeBC.pointAt( + // (triangle.edgeBC.length() * 0.5 - spacing / 2) / triangle.edgeBC.length(), + // ), // Right side midpoint + // new Line(triangle.centroid, triangle.pointB).pointAt( + // spacing / 2 / triangle.centroid.distance(triangle.pointB), + // ), // Centroid + // triangle.edgeAB.pointAt( + // (triangle.edgeAB.length() * 0.5 + spacing / 2) / triangle.edgeAB.length(), + // ), // Left side midpoint + // ]); + // const tradeoffRight = new Polygon([ + // triangle.edgeBC.pointAt( + // (triangle.edgeBC.length() * 0.5 + spacing / 2) / triangle.edgeBC.length(), + // ), // Right side midpoint + // triangle.pointC.clone(), // Right corner + // triangle.edgeCA.pointAt( + // (triangle.edgeCA.length() * 0.5 - spacing / 2) / triangle.edgeCA.length(), + // ), // Bottom side midpoint + // new Line(triangle.centroid, triangle.pointC).pointAt( + // spacing / 2 / triangle.centroid.distance(triangle.pointC), + // ), // Centroid + // ]); + // const tradeoffLeft = new Polygon([ + // triangle.edgeCA.pointAt( + // (triangle.edgeCA.length() * 0.5 + spacing / 2) / triangle.edgeCA.length(), + // ), // Bottom side midpoint + // triangle.pointA.clone(), // Left corner + // triangle.edgeAB.pointAt( + // (triangle.edgeAB.length() * 0.5 - spacing / 2) / triangle.edgeAB.length(), + // ), // Left side midpoint + // new Line(triangle.centroid, triangle.pointA).pointAt( + // spacing / 2 / triangle.centroid.distance(triangle.pointA), + // ), // Centroid + // ]); + // + // console.log(tradeoffTop); + // + // return ( + // + // + // + // + // + // {createText( + // firstLabel, + // tradeoffTop.center.x, + // tradeoffTop.center.y, + // 0.7 * tradeoffTop.width(), + // "middle", + // labelSize, + // "body", + // colors.seriesText[colorsStartIndex % colors.seriesText.length], + // )} + // {createText( + // secondLabel, + // tradeoffRight.center.x, + // tradeoffRight.center.y, + // 0.7 * tradeoffRight.width(), + // "middle", + // labelSize, + // "body", + // colors.seriesText[(colorsStartIndex + 1) % colors.seriesText.length], + // )} + // {createText( + // thirdLabel, + // tradeoffLeft.center.x, + // tradeoffLeft.center.y, + // 0.7 * tradeoffLeft.width(), + // "middle", + // labelSize, + // "body", + // colors.seriesText[(colorsStartIndex + 2) % colors.seriesText.length], + // )} + // + // ); +}; + +export default NeuralMagicTradeoffTriangle; diff --git a/src/components/graphs/utilities.jsx b/src/components/graphs/utilities.jsx new file mode 100644 index 00000000000..93819187886 --- /dev/null +++ b/src/components/graphs/utilities.jsx @@ -0,0 +1,64 @@ +import SHA256 from "crypto-js/sha256"; +import theme from "./theme"; + +const hashObjects = (objects, length = 32) => { + const combinedString = JSON.stringify(objects); + + return SHA256(combinedString).toString().substring(0, length); +}; + +const stringFormat = (value, valuesFormat) => { + try { + return value.toLocaleString(undefined, { + minimumFractionDigits: + valuesFormat === "#" ? 0 : valuesFormat.split(".")[1].length, + maximumFractionDigits: + valuesFormat === "#" ? 0 : valuesFormat.split(".")[1].length, + }); + } catch (error) { + console.error("Invalid valuesFormat:", valuesFormat); + return value; + } +}; + +const textDimensions = (text, style) => { + const fontProperties = theme.styles.font.properties[style]; + const canvas = document.createElement("canvas"); + const context = canvas.getContext("2d"); + context.font = `${fontProperties.fontStyle} ${fontProperties.fontWeight} ${fontProperties.fontSize} ${fontProperties.fontFamily}`; + const metrics = context.measureText(text); + const width = metrics.width; + const height = + metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent; + + return { width, height }; +}; + +const splitText = (text, maxWidth, style) => { + text = text + ""; // Ensure text is a string + const words = text.split(" "); + const lines = []; + let line = ""; + + for (const word of words) { + const testLine = line ? `${line} ${word}` : word; + const { width } = textDimensions(testLine, style); + + if (width <= maxWidth) { + line = testLine; + } else { + lines.push(line); + line = word; + } + } + + lines.push(line); + const dimensions = lines.map((line) => textDimensions(line, style)); + + return { + lines, + dimensions, + }; +}; + +export { hashObjects, stringFormat, textDimensions, splitText }; diff --git a/src/components/graphs/vector.jsx b/src/components/graphs/vector.jsx new file mode 100644 index 00000000000..a854014fd98 --- /dev/null +++ b/src/components/graphs/vector.jsx @@ -0,0 +1,431 @@ +class Point { + constructor(x, y) { + this.x = x; + this.y = y; + } + + equals(otherPoint) { + return this.x === otherPoint.x && this.y === otherPoint.y; + } + + toString() { + return `(${this.x}, ${this.y})`; + } + + clone() { + return new Point(this.x, this.y); + } + + normalize() { + const magnitude = Math.sqrt(this.x * this.x + this.y * this.y); + if (magnitude === 0) return; // Avoid division by zero + this.x /= magnitude; + this.y /= magnitude; + } + + rotate(angle) { + const radians = (angle * Math.PI) / 180; + const newX = this.x * Math.cos(radians) - this.y * Math.sin(radians); + const newY = this.x * Math.sin(radians) + this.y * Math.cos(radians); + this.x = newX; + this.y = newY; + } + + add(otherPoint) { + this.x += otherPoint.x; + this.y += otherPoint.y; + } + + subtract(otherPoint) { + this.x -= otherPoint.x; + this.y -= otherPoint.y; + } + + multiply(scalar) { + this.x *= scalar; + this.y *= scalar; + } + + divide(scalar) { + if (scalar === 0) return; // Avoid division by zero + this.x /= scalar; + this.y /= scalar; + } + + distance(otherPoint) { + const dx = this.x - otherPoint.x; + const dy = this.y - otherPoint.y; + return Math.sqrt(dx * dx + dy * dy); + } +} + +class Line { + constructor(start, end) { + this.start = start; + this.end = end; + } + + equals(otherLine) { + return this.start.equals(otherLine.start) && this.end.equals(otherLine.end); + } + + toString() { + return `[${this.start}, ${this.end}]`; + } + + clone() { + return new Line(this.start.clone(), this.end.clone()); + } + + length() { + return this.start.distance(this.end); + } + + slope() { + const dx = this.end.x - this.start.x; + const dy = this.end.y - this.start.y; + if (dx === 0) return Infinity; + return dy / dx; + } + + shift(dx, dy) { + this.start.x += dx; + this.start.y += dy; + this.end.x += dx; + this.end.y += dy; + } + + scale(factor, relativeTo = new Point(0, 0)) { + // Scale relative to a point (default is the origin) + this.start.x = relativeTo.x + factor * (this.start.x - relativeTo.x); + this.start.y = relativeTo.y + factor * (this.start.y - relativeTo.y); + this.end.x = relativeTo.x + factor * (this.end.x - relativeTo.x); + this.end.y = relativeTo.y + factor * (this.end.y - relativeTo.y); + } + + rotate(angle, relativeTo = new Point(0, 0)) { + const translation = new Point(-relativeTo.x, -relativeTo.y); + this.start.add(translation); + this.end.add(translation); + this.start.rotate(angle); + this.end.rotate(angle); + translation.multiply(-1); + this.start.add(translation); + this.end.add(translation); + } + + midPoint() { + return new Point( + (this.start.x + this.end.x) / 2, + (this.start.y + this.end.y) / 2, + ); + } + + pointAt(t) { + if (t < 0 || t > 1) return null; + + return new Point( + this.start.x + t * (this.end.x - this.start.x), + this.start.y + t * (this.end.y - this.start.y), + ); + } + + isParallel(otherLine) { + return this.slope() === otherLine.slope(); + } + + isPerpendicular(otherLine) { + return this.slope() * otherLine.slope() === -1; + } + + intersection(otherLine) { + const x1 = this.start.x; + const y1 = this.start.y; + const x2 = this.end.x; + const y2 = this.end.y; + const x3 = otherLine.start.x; + const y3 = otherLine.start.y; + const x4 = otherLine.end.x; + const y4 = otherLine.end.y; + + const denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + if (denominator === 0) return null; // Lines are parallel or coincident + + const t = ((x3 - x4) * (y1 - y3) + (y3 - y4) * (x1 - x3)) / denominator; + const u = ((x1 - x2) * (y1 - y3) + (y1 - y2) * (x3 - x1)) / denominator; + + if (t >= 0 && t <= 1 && u >= 0 && u <= 1) { + const intersectionX = x1 + t * (x2 - x1); + const intersectionY = y1 + t * (y2 - y1); + return new Point(intersectionX, intersectionY); + } + + return null; // Lines don't intersect within their defined segments + } + + dotProduct(otherLine) { + const dx1 = this.end.x - this.start.x; + const dy1 = this.end.y - this.start.y; + const dx2 = otherLine.end.x - otherLine.start.x; + const dy2 = otherLine.end.y - otherLine.start.y; + return dx1 * dx2 + dy1 * dy2; + } + + angle() { + const dx = this.end.x - this.start.x; + const dy = this.end.y - this.start.y; + return (Math.atan2(dy, dx) * 180) / Math.PI; + } +} + +class Triangle { + constructor(pointA, pointB, pointC) { + this.pointA = pointA; + this.pointB = pointB; + this.pointC = pointC; + this.edgeAB = new Line(pointA, pointB); + this.edgeBC = new Line(pointB, pointC); + this.edgeCA = new Line(pointC, pointA); + this.recalculateDerivedProperties(); // Initialize values + } + + recalculateDerivedProperties() { + // Angles (using Law of Cosines) + const a = this.edgeBC.length(); + const b = this.edgeCA.length(); + const c = this.edgeAB.length(); + this.angleA = + (Math.acos((b * b + c * c - a * a) / (2 * b * c)) * 180) / Math.PI; + this.angleB = + (Math.acos((a * a + c * c - b * b) / (2 * a * c)) * 180) / Math.PI; + this.angleC = 180 - this.angleA - this.angleB; + + // Centroid (average of vertices) + this.centroid = new Point( + (this.pointA.x + this.pointB.x + this.pointC.x) / 3, + (this.pointA.y + this.pointB.y + this.pointC.y) / 3, + ); + } + + equals(otherTriangle) { + const points1 = [this.pointA, this.pointB, this.pointC].sort((a, b) => { + if (a.x === b.x) return a.y - b.y; + return a.x - b.x; + }); + + const points2 = [ + otherTriangle.pointA, + otherTriangle.pointB, + otherTriangle.pointC, + ].sort((a, b) => { + if (a.x === b.x) return a.y - b.y; + return a.x - b.x; + }); + + return ( + points1[0].equals(points2[0]) && + points1[1].equals(points2[1]) && + points1[2].equals(points2[2]) + ); + } + + toString() { + return `Triangle: ${this.pointA}, ${this.pointB}, ${this.pointC}`; + } + + clone() { + return new Triangle( + this.pointA.clone(), + this.pointB.clone(), + this.pointC.clone(), + ); + } + + perimeter() { + return this.edgeAB.length() + this.edgeBC.length() + this.edgeCA.length(); + } + + area() { + const s = this.perimeter() / 2; + return Math.sqrt( + s * + (s - this.edgeAB.length()) * + (s - this.edgeBC.length()) * + (s - this.edgeCA.length()), + ); + } +} + +class Polygon { + constructor(points) { + this.points = points; + this.recalculateDerivedProperties(); + } + + recalculateDerivedProperties() { + this.edges = this.calculateEdges(); + this.angles = this.calculateAngles(); + this.center = this.calculateCentroid(); + } + + calculateEdges() { + const edges = []; + for (let i = 0; i < this.points.length; i++) { + edges.push( + new Line(this.points[i], this.points[(i + 1) % this.points.length]), + ); + } + return edges; + } + + calculateAngles() { + // ... (Implementation to calculate angles using vectors and trigonometry) + } + + calculateCentroid() { + let sumX = 0; + let sumY = 0; + for (const point of this.points) { + sumX += point.x; + sumY += point.y; + } + return new Point(sumX / this.points.length, sumY / this.points.length); + } + + equals(otherPolygon) { + if (this.points.length !== otherPolygon.points.length) return false; + + // Find the starting point with the smallest coordinates in both polygons + let minIndex1 = 0, + minIndex2 = 0; + for (let i = 1; i < this.points.length; i++) { + if ( + this.points[i].y < this.points[minIndex1].y || + (this.points[i].y === this.points[minIndex1].y && + this.points[i].x < this.points[minIndex1].x) + ) { + minIndex1 = i; + } + if ( + otherPolygon.points[i].y < otherPolygon.points[minIndex2].y || + (otherPolygon.points[i].y === otherPolygon.points[minIndex2].y && + otherPolygon.points[i].x < otherPolygon.points[minIndex2].x) + ) { + minIndex2 = i; + } + } + + // Create sorted arrays of points, starting from the smallest coordinate + const sortedPoints1 = this.getSortedPointsFromIndex(minIndex1); + const sortedPoints2 = otherPolygon.getSortedPointsFromIndex(minIndex2); + + // Compare sorted points + for (let i = 0; i < sortedPoints1.length; i++) { + if (!sortedPoints1[i].equals(sortedPoints2[i])) { + return false; + } + } + return true; + } + + toString() { + return `Polygon: ${this.points.map((p) => p.toString()).join(", ")}`; + } + + clone() { + return new Polygon(this.points.map((p) => p.clone())); + } + + getSortedPointsFromIndex(startIndex) { + const sortedPoints = this.points + .slice(startIndex) + .concat(this.points.slice(0, startIndex)); + return sortedPoints.sort((a, b) => a.x - b.x || a.y - b.y); // Sort by x, then y + } + + width() { + const xCoordinates = this.points.map((point) => point.x); + return Math.max(...xCoordinates) - Math.min(...xCoordinates); + } + + height() { + const yCoordinates = this.points.map((point) => point.y); + return Math.max(...yCoordinates) - Math.min(...yCoordinates); + } + + perimeter() { + return this.edges.reduce((sum, edge) => sum + edge.length(), 0); + } + + area() { + let area = 0; + + for (let i = 1; i < this.points.length - 1; i++) { + const triangle = new Triangle( + this.points[0], + this.points[i], + this.points[i + 1], + ); + area += triangle.area(); + } + + return Math.abs(area); + } + + isSquare() { + if (this.points.length !== 4) return false; + + const side1 = this.edges[0].length(); + + for (let i = 1; i < 4; i++) { + if (this.edges[i].length() !== side1) return false; + } + + for (let i = 0; i < 4; i++) { + const v1 = this.edges[i].end.clone().subtract(this.edges[i].start); + const v2 = this.edges[(i + 1) % 4].end + .clone() + .subtract(this.edges[(i + 1) % 4].start); + if (v1.dotProduct(v2) === 0) return true; + } + + return false; + } + + isRectangle() { + if (this.points.length !== 4) return false; + + if ( + !this.edges[0].isParallel(this.edges[2]) || + !this.edges[1].isParallel(this.edges[3]) + ) { + return false; + } + + for (let i = 0; i < 4; i++) { + const v1 = this.edges[i].end.clone().subtract(this.edges[i].start); + const v2 = this.edges[(i + 1) % 4].end + .clone() + .subtract(this.edges[(i + 1) % 4].start); + if (v1.dotProduct(v2) === 0) return true; + } + + return false; + } +} + +class Rectangle extends Polygon { + constructor(x, y, width, height) { + super([ + new Point(x, y), + new Point(x + width, y), + new Point(x + width, y + height), + new Point(x, y + height), + ]); + + this.x = x; + this.y = y; + } +} + +export { Point, Line, Triangle, Polygon, Rectangle }; diff --git a/src/components/mdx-provider/index.jsx b/src/components/mdx-provider/index.jsx deleted file mode 100644 index fd6d7a46d39..00000000000 --- a/src/components/mdx-provider/index.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { MDXProvider } from '@mdx-js/react'; - - - -const components = { - -}; - -export default function DocsMDXProvider({ children }) { - return {children}; -} diff --git a/src/components/version-injector/index.jsx b/src/components/version-injector/index.jsx index b860a0d5876..4ac14693b18 100644 --- a/src/components/version-injector/index.jsx +++ b/src/components/version-injector/index.jsx @@ -1,66 +1,124 @@ -import React from 'react'; -import {useDoc} from '@docusaurus/theme-common/internal'; -import usePluginData from '@docusaurus/useGlobalData'; +import React from "react"; +import { useDoc } from "@docusaurus/theme-common/internal"; +import usePluginData from "@docusaurus/useGlobalData"; +const processChildren = ( + child, + currentVersion, + lastVersion, + targetVersion, + targetProducts, + prepend, + currentTag, + ignoreNightly, +) => { + if (typeof child === "string") { + let version = currentVersion; + let products = [...targetProducts]; -const processChildren = (child, currentVersion, lastVersion, targetVersion, targetProducts, prepend, currentTag, ignoreNightly) => { - if (typeof child === 'string') { - let version = currentVersion; - let products = [...targetProducts]; - - if (version === 'current') { - if (!ignoreNightly && targetProducts) { - for (let i = 0; i < products.length; i++) { - let product = products[i]; - if (product.indexOf("[") > -1) { - const split = product.split('['); - product = `${split[0]}-nightly[${split[1]}`; - } else { - product = `${product}-nightly`; - } - products[i] = product; - } - } - version = currentTag; - } else if (version === lastVersion) { - version = ''; - } else if (prepend) { - version = `${prepend}${version}`; - } - - let replaced = child.replace(new RegExp(targetVersion, 'g'), version); - + if (version === "current") { + if (!ignoreNightly && targetProducts) { for (let i = 0; i < products.length; i++) { - replaced = replaced.replace(new RegExp(targetProducts[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), products[i]); + let product = products[i]; + if (product.indexOf("[") > -1) { + const split = product.split("["); + product = `${split[0]}-nightly[${split[1]}`; + } else { + product = `${product}-nightly`; + } + products[i] = product; } - - return replaced; + } + version = currentTag; + } else if (version === lastVersion) { + version = ""; + } else if (prepend) { + version = `${prepend}${version}`; } - if (React.isValidElement(child)) { - return React.cloneElement(child, child.props, processChildren(child.props.children, currentVersion, lastVersion, targetVersion, targetProducts, prepend, currentTag, ignoreNightly)); - } + let replaced = child.replace(new RegExp(targetVersion, "g"), version); - if (Array.isArray(child)) { - return child.map(c => processChildren(c, currentVersion, lastVersion, targetVersion, targetProducts, prepend, currentTag, ignoreNightly)); + for (let i = 0; i < products.length; i++) { + replaced = replaced.replace( + new RegExp( + targetProducts[i].replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), + "g", + ), + products[i], + ); } - return child; -}; + return replaced; + } + + if (React.isValidElement(child)) { + return React.cloneElement( + child, + child.props, + processChildren( + child.props.children, + currentVersion, + lastVersion, + targetVersion, + targetProducts, + prepend, + currentTag, + ignoreNightly, + ), + ); + } + if (Array.isArray(child)) { + return child.map((c) => + processChildren( + c, + currentVersion, + lastVersion, + targetVersion, + targetProducts, + prepend, + currentTag, + ignoreNightly, + ), + ); + } + + return child; +}; -const VersionInjector = ({ children, targetVersion = 'VERSION', targetProduct = 'PRODUCT', prepend = '', currentTag = '', ignoreNightly = false, ignoreLastVersion = false}) => { - const { metadata } = useDoc(); - const pluginData = usePluginData('docusaurus-plugin-content-docs')['docusaurus-plugin-content-docs']; - const versions = pluginData.default.versions; - const lastVersionData = versions.find(version => version.isLast); - const lastVersion = ignoreLastVersion ? null : lastVersionData.name; +const VersionInjector = ({ + children, + targetVersion = "VERSION", + targetProduct = "PRODUCT", + prepend = "", + currentTag = "", + ignoreNightly = false, + ignoreLastVersion = false, +}) => { + const { metadata } = useDoc(); + const pluginData = usePluginData("docusaurus-plugin-content-docs")[ + "docusaurus-plugin-content-docs" + ]; + const versions = pluginData.default.versions; + const lastVersionData = versions.find((version) => version.isLast); + const lastVersion = ignoreLastVersion ? null : lastVersionData.name; - const currentVersion = metadata.version; - const targetProducts = Array.isArray(targetProduct) ? targetProduct : [targetProduct]; - const processedChildren = processChildren(children, currentVersion, lastVersion, targetVersion, targetProducts, prepend, currentTag, ignoreNightly); + const currentVersion = metadata.version; + const targetProducts = Array.isArray(targetProduct) + ? targetProduct + : [targetProduct]; + const processedChildren = processChildren( + children, + currentVersion, + lastVersion, + targetVersion, + targetProducts, + prepend, + currentTag, + ignoreNightly, + ); - return <>{processedChildren}; + return <>{processedChildren}; }; -export default VersionInjector; \ No newline at end of file +export default VersionInjector; diff --git a/src/css/_mixins.scss b/src/css/_mixins.scss index fe2392d509b..952c9ba9184 100644 --- a/src/css/_mixins.scss +++ b/src/css/_mixins.scss @@ -5,4 +5,4 @@ -webkit-box-orient: vertical; text-overflow: ellipsis; white-space: unset; -} \ No newline at end of file +} diff --git a/src/css/_screen-layouts.scss b/src/css/_screen-layouts.scss index a23634e5321..8d5f8cf1110 100644 --- a/src/css/_screen-layouts.scss +++ b/src/css/_screen-layouts.scss @@ -110,4 +110,4 @@ $columns-right-bar: 0; @include layout-xl; @content; } -} \ No newline at end of file +} diff --git a/src/css/custom.scss b/src/css/custom.scss index edd568778c7..37daa4a9586 100644 --- a/src/css/custom.scss +++ b/src/css/custom.scss @@ -1,9 +1,30 @@ -@import '_screen-layouts'; +@import "_screen-layouts"; -html, :root { +@font-face { + font-family: "Spezia"; + src: url("/fonts/SpeziaWeb-Regular.woff") format("woff"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: "Spezia Medium"; + src: url("/fonts/SpeziaWeb-Medium.woff") format("woff"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: "Spezia Mono"; + src: url("/fonts/SpeziaMonoWeb-Medium.woff") format("woff"); + font-weight: normal; + font-style: normal; +} +html, +:root { /* Heading Fonts */ - --ifm-heading-font-family: 'Space Grotesk', sans-serif; + --ifm-heading-font-family: "Space Grotesk", sans-serif; --ifm-heading-font-weight: 400; --ifm-h1-font-size: 48px; --ifm-h2-font-size: 32px; @@ -13,20 +34,20 @@ html, :root { --ifm-h6-font-size: 18px; /* Content Fonts */ - --ifm-font-family-base: 'Inter', sans-serif; + --ifm-font-family-base: "Inter", sans-serif; --ifm-font-size-base: 16px; /* Body 1 */ --ifm-font-weight-semibold: 600; --ifm-link-hover-decoration: underline; /* Text Colors */ --ifm-font-color-base: #222222; - --ifm-color-content-secondary: #5D6C6D; + --ifm-color-content-secondary: #5d6c6d; --ifm-font-color-base-inverse: #ffffff; --ifm-link-color: #3d86b7; /* Background / Surface Colors */ --ifm-background-color: #f6fbfe; - --custom-background-blue-dark: #052D52; + --custom-background-blue-dark: #052d52; --custom-background-blue-light: #e1f0fd; --custom-surface-color: #fdfdfe; --custom-surface-blue: #c5eefb; @@ -58,7 +79,8 @@ Layouts */ @include for-xl-screens { - html, :root { + html, + :root { --gutter: 32px; --margin: auto; --margin-px: calc(100vw - 1600px) / 2; @@ -74,7 +96,8 @@ Layouts } @include for-lg-screens { - html, :root { + html, + :root { --gutter: 32px; --margin: 32px; --margin-px: 32px; @@ -90,7 +113,8 @@ Layouts } @include for-md-screens { - html, :root { + html, + :root { --gutter: 16px; --margin: 32px; --margin-px: 16px; @@ -106,7 +130,8 @@ Layouts } @include for-sm-screens { - html, :root { + html, + :root { --gutter: 16px; --margin: 32px; --columns: 4; @@ -121,7 +146,8 @@ Layouts } @include for-xs-screens { - html, :root { + html, + :root { --gutter: 8px; --margin: 16px; --columns: 4; @@ -135,7 +161,6 @@ Layouts } } - /** Navbar customizations */ @@ -156,7 +181,9 @@ Navbar customizations margin-right: var(--margin); } -.navbar__title, .navbar__inner, .navbar__link { +.navbar__title, +.navbar__inner, +.navbar__link { color: var(--ifm-font-color-base-inverse); } @@ -182,7 +209,7 @@ Search customizations /* Modal */ /*--docsearch-container-background: var(--custom-surface-color);*/ --docsearch-modal-background: var(--ifm-background-color); - --docsearch-footer-background: var(--ifm-background-color) + --docsearch-footer-background: var(--ifm-background-color); } .DocSearch-Button-Keys { @@ -195,7 +222,6 @@ Search customizations width: 128px; } - /** Left nav cutomizations */ @@ -207,12 +233,12 @@ Left nav cutomizations padding-top: 16px; } -.theme-doc-sidebar-item-category, .theme-doc-sidebar-item-link { +.theme-doc-sidebar-item-category, +.theme-doc-sidebar-item-link { font-size: var(--ifm-h4-font-size); font-family: var(--ifm-heading-font-family); } - /** Footer customizations */ @@ -231,7 +257,8 @@ Footer customizations padding-bottom: 20px; } - .footer__links, .footer__bottom { + .footer__links, + .footer__bottom { margin: 0; text-align: start; } @@ -245,7 +272,6 @@ Footer customizations } } - /** Right bar customizations */ @@ -259,7 +285,7 @@ Right bar customizations .table-of-contents { padding: 0; border-left: none; - font-size: 1.0rem; + font-size: 1rem; li { margin: 8px 0; diff --git a/src/theme/CodeBlock/Container/index.js b/src/theme/CodeBlock/Container/index.js index ce665eb41bc..b95288a7296 100644 --- a/src/theme/CodeBlock/Container/index.js +++ b/src/theme/CodeBlock/Container/index.js @@ -1,9 +1,9 @@ -import React from 'react'; -import clsx from 'clsx'; -import {ThemeClassNames, usePrismTheme} from '@docusaurus/theme-common'; -import {getPrismCssVariables} from '@docusaurus/theme-common/internal'; -import styles from './styles.module.css'; -export default function CodeBlockContainer({as: As, ...props}) { +import React from "react"; +import clsx from "clsx"; +import { ThemeClassNames, usePrismTheme } from "@docusaurus/theme-common"; +import { getPrismCssVariables } from "@docusaurus/theme-common/internal"; +import styles from "./styles.module.css"; +export default function CodeBlockContainer({ as: As, ...props }) { const prismTheme = usePrismTheme(); const prismCssVariables = getPrismCssVariables(prismTheme); return ( diff --git a/src/theme/CodeBlock/Content/Element.js b/src/theme/CodeBlock/Content/Element.js index dbe56049709..4e4e1b59383 100644 --- a/src/theme/CodeBlock/Content/Element.js +++ b/src/theme/CodeBlock/Content/Element.js @@ -1,16 +1,17 @@ -import React from 'react'; -import clsx from 'clsx'; -import Container from '@theme/CodeBlock/Container'; -import styles from './styles.module.css'; +import React from "react"; +import clsx from "clsx"; +import Container from "@theme/CodeBlock/Container"; +import styles from "./styles.module.css"; //
 tags in markdown map to CodeBlocks. They may contain JSX children. When
 // the children is not a simple string, we just return a styled block without
 // actually highlighting.
-export default function CodeBlockJSX({children, className}) {
+export default function CodeBlockJSX({ children, className }) {
   return (
     
+      className={clsx(styles.codeBlockStandalone, "thin-scrollbar", className)}
+    >
       {children}
     
   );
diff --git a/src/theme/CodeBlock/Content/String.js b/src/theme/CodeBlock/Content/String.js
index f16474b96f8..4e5e409e510 100644
--- a/src/theme/CodeBlock/Content/String.js
+++ b/src/theme/CodeBlock/Content/String.js
@@ -1,19 +1,19 @@
-import React from 'react';
-import clsx from 'clsx';
-import {useThemeConfig, usePrismTheme} from '@docusaurus/theme-common';
+import React from "react";
+import clsx from "clsx";
+import { useThemeConfig, usePrismTheme } from "@docusaurus/theme-common";
 import {
   parseCodeBlockTitle,
   parseLanguage,
   parseLines,
   containsLineNumbers,
   useCodeWordWrap,
-} from '@docusaurus/theme-common/internal';
-import {Highlight} from 'prism-react-renderer';
-import Line from '@theme/CodeBlock/Line';
-import CopyButton from '@theme/CodeBlock/CopyButton';
-import WordWrapButton from '@theme/CodeBlock/WordWrapButton';
-import Container from '@theme/CodeBlock/Container';
-import styles from './styles.module.css';
+} from "@docusaurus/theme-common/internal";
+import { Highlight } from "prism-react-renderer";
+import Line from "@theme/CodeBlock/Line";
+import CopyButton from "@theme/CodeBlock/CopyButton";
+import WordWrapButton from "@theme/CodeBlock/WordWrapButton";
+import Container from "@theme/CodeBlock/Container";
+import styles from "./styles.module.css";
 
 // Prism languages are always lowercase
 // We want to fail-safe and allow both "php" and "PHP"
@@ -23,30 +23,34 @@ function normalizeLanguage(language) {
 }
 
 function parseOutput(content) {
-  if (!content.includes('') || !content.includes('')) {
+  if (!content.includes("") || !content.includes("")) {
     return { code: content, output: null };
   }
 
   const codeRegex = /.*([\s\S]*?)<\/output>/i;
-  const code = content.replace(codeRegex, '').trim();
+  const code = content.replace(codeRegex, "").trim();
   let output = content.match(codeRegex)?.[1].trim();
 
   const commentRegex = /^[ \t]*(\/\/|\/\*|\*\/|#|--)/gm;
-  output = output.split('\n').map(line => line.replace(commentRegex, '')).join('\n').trim();
+  output = output
+    .split("\n")
+    .map((line) => line.replace(commentRegex, ""))
+    .join("\n")
+    .trim();
 
   return { code, output };
 }
 
 export default function CodeBlockString({
   children,
-  className: blockClassName = '',
+  className: blockClassName = "",
   metastring,
   title: titleProp,
   showLineNumbers: showLineNumbersProp,
   language: languageProp,
 }) {
   const {
-    prism: {defaultLanguage, magicComments},
+    prism: { defaultLanguage, magicComments },
   } = useThemeConfig();
   const language = normalizeLanguage(
     languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage,
@@ -58,7 +62,7 @@ export default function CodeBlockString({
   // "title=\"xyz\"" => title: "\"xyz\""
   const title = parseCodeBlockTitle(metastring) || titleProp;
   const parsedCode = parseOutput(children);
-  const {lineClassNames, code} = parseLines(parsedCode.code, {
+  const { lineClassNames, code } = parseLines(parsedCode.code, {
     metastring,
     language,
     magicComments,
@@ -73,22 +77,25 @@ export default function CodeBlockString({
         language &&
           !blockClassName.includes(`language-${language}`) &&
           `language-${language}`,
-      )}>
+      )}
+    >
       {title && 
{title}
}
- - {({className, style, tokens, getLineProps, getTokenProps}) => ( + + {({ className, style, tokens, getLineProps, getTokenProps }) => (
+              className={clsx(className, styles.codeBlock, "thin-scrollbar")}
+              style={style}
+            >
               
+                )}
+              >
                 {tokens.map((line, i) => (
                   
 
         {parsedCode.output && (
-            
-
-
- {parsedCode.output} -
+
+
+
+ {parsedCode.output}
+
)}
diff --git a/src/theme/CodeBlock/CopyButton/index.js b/src/theme/CodeBlock/CopyButton/index.js index fd430b473cb..4f6c3b736b3 100644 --- a/src/theme/CodeBlock/CopyButton/index.js +++ b/src/theme/CodeBlock/CopyButton/index.js @@ -1,11 +1,11 @@ -import React, {useCallback, useState, useRef, useEffect} from 'react'; -import clsx from 'clsx'; -import copy from 'copy-text-to-clipboard'; -import {translate} from '@docusaurus/Translate'; -import IconCopy from '@theme/Icon/Copy'; -import IconSuccess from '@theme/Icon/Success'; -import styles from './styles.module.css'; -export default function CopyButton({code, className}) { +import React, { useCallback, useState, useRef, useEffect } from "react"; +import clsx from "clsx"; +import copy from "copy-text-to-clipboard"; +import { translate } from "@docusaurus/Translate"; +import IconCopy from "@theme/Icon/Copy"; +import IconSuccess from "@theme/Icon/Success"; +import styles from "./styles.module.css"; +export default function CopyButton({ code, className }) { const [isCopied, setIsCopied] = useState(false); const copyTimeout = useRef(undefined); const handleCopyCode = useCallback(() => { @@ -22,28 +22,29 @@ export default function CopyButton({code, className}) { aria-label={ isCopied ? translate({ - id: 'theme.CodeBlock.copied', - message: 'Copied', - description: 'The copied button label on code blocks', + id: "theme.CodeBlock.copied", + message: "Copied", + description: "The copied button label on code blocks", }) : translate({ - id: 'theme.CodeBlock.copyButtonAriaLabel', - message: 'Copy code to clipboard', - description: 'The ARIA label for copy code blocks button', + id: "theme.CodeBlock.copyButtonAriaLabel", + message: "Copy code to clipboard", + description: "The ARIA label for copy code blocks button", }) } title={translate({ - id: 'theme.CodeBlock.copy', - message: 'Copy', - description: 'The copy button label on code blocks', + id: "theme.CodeBlock.copy", + message: "Copy", + description: "The copy button label on code blocks", })} className={clsx( - 'clean-btn', + "clean-btn", className, styles.copyButton, isCopied && styles.copyButtonCopied, )} - onClick={handleCopyCode}> + onClick={handleCopyCode} + >