diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 664fe923..db455aa7 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -122,6 +122,9 @@ const config: Config = { routeBasePath: "/", sidebarPath: "./sidebars.js", docItemComponent: "@theme/ApiItem", // Derived from docusaurus-theme-openapi + remarkPlugins: [ + [require('./plugins/remark-table-wide-cells'), { threshold: 40 }], + ], // Please change this to your repo. // Remove this to remove the "edit this page" links. // editUrl: diff --git a/plugins/remark-table-wide-cells.js b/plugins/remark-table-wide-cells.js new file mode 100644 index 00000000..c16fa40d --- /dev/null +++ b/plugins/remark-table-wide-cells.js @@ -0,0 +1,65 @@ +/** + * Remark plugin that detects table columns with long text content + * and tags all cells in those columns with a `wide-cell` CSS class. + * + * This enables targeted CSS word-wrapping on only the columns that need it, + * keeping short columns compact. + */ +const { visit } = require('unist-util-visit'); + +/** Recursively extract plain text from an MDAST node. */ +function extractText(node) { + if (node.type === 'text' || node.type === 'inlineCode') { + return node.value || ''; + } + if (node.children) { + return node.children.map(extractText).join(''); + } + return ''; +} + +function remarkTableWideCells({ threshold = 100 } = {}) { + return (tree) => { + visit(tree, 'table', (table) => { + if (!table.children || table.children.length === 0) return; + + // Determine the number of columns from the first row + const numCols = table.children[0].children + ? table.children[0].children.length + : 0; + if (numCols === 0) return; + + // Check each column: does ANY cell exceed the threshold? + const wideColumns = new Set(); + for (const row of table.children) { + if (!row.children) continue; + for (let colIdx = 0; colIdx < row.children.length; colIdx++) { + if (wideColumns.has(colIdx)) continue; + const cell = row.children[colIdx]; + const text = extractText(cell); + if (text.length > threshold) { + wideColumns.add(colIdx); + } + } + } + + if (wideColumns.size === 0) return; + + // Tag all cells in wide columns + for (const row of table.children) { + if (!row.children) continue; + for (let colIdx = 0; colIdx < row.children.length; colIdx++) { + if (!wideColumns.has(colIdx)) continue; + const cell = row.children[colIdx]; + cell.data = cell.data || {}; + cell.data.hProperties = cell.data.hProperties || {}; + let existing = cell.data.hProperties.className || []; + if (typeof existing === 'string') existing = [existing]; + cell.data.hProperties.className = Array.from(new Set([...existing, 'wide-cell'])); + } + } + }); + }; +} + +module.exports = remarkTableWideCells; diff --git a/src/css/custom.css b/src/css/custom.css index f2ca9441..e1cc0cf5 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -599,6 +599,27 @@ html[data-theme='dark'] div[class*="language-shell"] code::before { text-decoration: underline; } +/************** +** TABLES — responsive with targeted wrapping +***************/ + +/* Make tables responsive with horizontal scroll */ +.markdown table { + display: block; + max-width: 100%; + overflow-x: auto; + white-space: nowrap; +} + +/* Allow word-wrapping in columns tagged as wide by remark-table-wide-cells */ +.markdown table td.wide-cell, +.markdown table th.wide-cell { + white-space: normal; + overflow-wrap: anywhere; + word-break: normal; + min-width: 200px; +} + /************** ** OPENTDF LANDING — DARK DESIGN TOKENS ***************/