diff --git a/website/package-lock.json b/website/package-lock.json index 5fdf491f1cf..df0c9652529 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -27,6 +27,7 @@ "gray-matter": "^4.0.3", "hast-util-is-element": "^1.1.0", "js-yaml": "^4.1.0", + "markdown-to-jsx": "^7.5.0", "mobx": "^6.3.9", "node-polyfill-webpack-plugin": "^1.1.4", "papaparse": "^5.3.2", @@ -17038,6 +17039,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/markdown-to-jsx": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.5.0.tgz", + "integrity": "sha512-RrBNcMHiFPcz/iqIj0n3wclzHXjwS7mzjBNWecKKVhNTIxQepIix6Il/wZCn2Cg5Y1ow2Qi84+eJrryFRWBEWw==", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", diff --git a/website/package.json b/website/package.json index 51edae4bf17..a16c8f9db9b 100644 --- a/website/package.json +++ b/website/package.json @@ -30,6 +30,7 @@ "gray-matter": "^4.0.3", "hast-util-is-element": "^1.1.0", "js-yaml": "^4.1.0", + "markdown-to-jsx": "^7.5.0", "mobx": "^6.3.9", "node-polyfill-webpack-plugin": "^1.1.4", "papaparse": "^5.3.2", diff --git a/website/src/components/sortableTable/index.js b/website/src/components/sortableTable/index.js new file mode 100644 index 00000000000..93d54252c94 --- /dev/null +++ b/website/src/components/sortableTable/index.js @@ -0,0 +1,114 @@ +import React, { useState, useMemo } from 'react'; +import Markdown from 'markdown-to-jsx'; + +const stripMarkdown = (text) => { + let strippedText = text.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1'); + strippedText = strippedText.replace(/[_*`~]/g, ''); + return strippedText; +}; + +const parseMarkdownTable = (markdown) => { + const rows = markdown.trim().split('\n'); + const headers = rows[0].split('|').map((header) => header.trim()).filter(Boolean); + + const alignmentsRow = rows[1].split('|').map((align) => align.trim()).filter(Boolean); + const columnAlignments = alignmentsRow.map((alignment) => { + if (alignment.startsWith(':') && alignment.endsWith(':')) { + return 'center'; + } else if (alignment.startsWith(':')) { + return 'left'; + } else if (alignment.endsWith(':')) { + return 'right'; + } else { + return 'left'; + } + }); + + const data = rows.slice(2).map(row => row.split('|').map(cell => cell.trim()).filter(Boolean)); + + return { headers, data, columnAlignments }; +}; + +const SortableTable = ({ children }) => { + const { headers, data: initialData, columnAlignments } = useMemo( + () => parseMarkdownTable(children), + [children] + ); + + const [data, setData] = useState(initialData); + const [sortConfig, setSortConfig] = useState({ key: '', direction: 'asc' }); + + const sortTable = (keyIndex) => { + const newDirection = (sortConfig.key === keyIndex && sortConfig.direction === 'asc') ? 'desc' : 'asc'; + setSortConfig({ key: keyIndex, direction: newDirection }); + + const sortedData = [...data].sort((a, b) => { + const aVal = stripMarkdown(a[keyIndex]); + const bVal = stripMarkdown(b[keyIndex]); + if (aVal < bVal) return newDirection === 'asc' ? -1 : 1; + if (aVal > bVal) return newDirection === 'asc' ? 1 : -1; + return 0; + }); + + setData(sortedData); + }; + + return ( +
sortTable(index)}
+ style={{
+ cursor: 'pointer',
+ position: 'relative',
+ textAlign: columnAlignments[index],
+ padding: '10px'
+ }}
+ >
+
+ {header}
+
+ ↑
+
+
+ ↓
+
+
+ |
+ ))}
+
---|
+ |
+ ))}
+