Skip to content

Commit

Permalink
feat: render md table
Browse files Browse the repository at this point in the history
  • Loading branch information
p208p2002 committed Aug 31, 2024
1 parent 64cd43f commit 11180b6
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 8 deletions.
8 changes: 8 additions & 0 deletions src/modules/MdRender/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,12 @@
padding-right: 5px;
margin-left: 6px;
color: var(--text-2);
}
#MD tr:first-child{
border-width: 0px 0px 2px 0px;
border-style: solid;
border-color: var(--main-1);;
}
#MD td{
padding: 5px;
}
29 changes: 21 additions & 8 deletions src/modules/MdRender/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Gitalk from 'gitalk'
import Darkmode from 'drkmd-js'
import ExifReader from 'exifreader';
import { siNikon, siLens, siApple } from 'simple-icons'

import { mdTableToHTML } from './md-table-to-html'

const axios = require('axios');

Expand Down Expand Up @@ -169,7 +169,7 @@ export default function MdRender({ doc_id }) {
setPageTitle(`${gistTitle} - ${BLOG_NAME}`)
setPageDescription(gistContent.replaceAll("#", " ").slice(0, 500))
})
.catch(()=>{
.catch(() => {
window.location.href = "/?page=code-404"
})
// eslint-disable-next-line
Expand All @@ -188,7 +188,7 @@ export default function MdRender({ doc_id }) {
})
gitalk.render("comments")
}
}, [doc_id,postTitle])
}, [doc_id, postTitle])

let { date = "", tags = [] } = documentInfo

Expand Down Expand Up @@ -286,8 +286,21 @@ export default function MdRender({ doc_id }) {
return <div className={className} {...props}>{children}</div>
}
},
p({ node, inline, className, children, ...props }) {
if (Array.isArray(children)) {
children = children.map((child, childIdx) => {
if (typeof (child) === "string" && child.length > 1 && child[0] === "|") {
return <div className="md-table-container" key={childIdx}
dangerouslySetInnerHTML={{ __html: mdTableToHTML(child).html }}
/>
}
return child
})
}
return <p className={className} {...props} >{children}</p>
},
span({ node, inline, className, children, ...props }) {

if (className === "math math-inline") {
let math_tex = children[0] || "";
let math_html = katex.renderToString(math_tex, {
Expand All @@ -297,7 +310,7 @@ export default function MdRender({ doc_id }) {
});
return <span className={className} {...props} dangerouslySetInnerHTML={{ __html: math_html }} />
}

else {
return <span className={className} {...props}>{children}</span>
}
Expand Down Expand Up @@ -343,9 +356,9 @@ export default function MdRender({ doc_id }) {
})
.catch(() => {
// image without exif info
let exifText = document.getElementById(img_url+"EXIF-Text")
let exifText = document.getElementById(img_url + "EXIF-Text")
try {
exifText.parentNode.removeChild(exifText)
exifText.parentNode.removeChild(exifText)
} catch (error) {
// pass
}
Expand All @@ -358,7 +371,7 @@ export default function MdRender({ doc_id }) {
<svg id={img_url + "SVG"} role="img" viewBox="0 0 24 24">
<path id={img_url + "SVGPath"} d={siLens.path} />
</svg>
<span style={{fontSize:'normal'}}>&nbsp;|&nbsp;<span style={{fontSize:'italic'}} id={img_url + "Model"} /></span>
<span style={{ fontSize: 'normal' }}>&nbsp;|&nbsp;<span style={{ fontSize: 'italic' }} id={img_url + "Model"} /></span>
</span>
<span className="exif-item" id={img_url + "FocalLength"} />
<span className="exif-item" id={img_url + "FNumber"} />
Expand Down
133 changes: 133 additions & 0 deletions src/modules/MdRender/md-table-to-html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
const alignments = ['left', 'center', 'right'];

/**
* Converts a markdown table string into HTML.
* @param {string} md Markdown table as a string.
*/
export function mdTableToHTML(md) {
var lines = getLines(md);
var isHeader = true;
var table = new HTMLTable();
var colAlignments = [];
lines.forEach(function(line) {
if (isHeaderSeparation(line)) {
isHeader = false;
colAlignments = getAlignment(line);
return;
}
var vals = splitLine(line);
table.addRow(vals, isHeader);
});
table.setAlignments(colAlignments);
return {
html: table.getHTML(),
htmlString: table.getHTMLString()
}
}

/**
* Converts a document into an array of string, where each element corresponds to one row.
* @param {string} doc Document
* @returns {string[]} The lines of the document.
*/
function getLines(doc) {
return doc.replace(/\r\n/g,"\n").split("\n")
}

/**
* Checks whether a line contains the table syntax that separates table header from body.
* Example for a separation line: "| --- |:---:| ---:|"
* @param {string} line A line of a markdown document.
* @returns {boolean} True if the line is a separation line.
*/
function isHeaderSeparation(line) {
let match = line.match(/(\|\s*(:)?\s*-{3,}\s*(:)?\s*)+\|/g);
if (!Array.isArray(match)) return false;
return match.length > 0;
}

/**
* Reads the column alignment information from a separation line.
* E.g. "| --- |:---:| ---:|" is ['left', 'center', 'right']
* @param {string} headerLine A line for which isHeaderSeparation returns true.
* @returns {string[]} The alignment of each column, entries are in ['left', 'center', 'right'].
*/
function getAlignment(headerLine) {
let parts = splitLine(headerLine);

return parts.map(col => {
if (col.length === 0) return alignments[0];
let firstChar = col.charAt(0),
lastChar = col.slice(-1);
if (firstChar === ':' && lastChar === ':') return alignments[1];
if (lastChar === ':') return alignments[2];
return alignments[0];
})
}

/**
* Converts an alignment into the corresponding style tag.
* Empty string for alignment: left (default).
* @param {string} alignment Alignment, i.e. either of ['left', 'center', 'right'].
* @returns {string} The style attribute with text-alignment.
*/
function getStyleAttribute(alignment) {
if (alignment === alignments[0]) return '';
return ' style="text-align: ' + alignment + ';"';
}

/**
* Splits a Markdown table line into its trimmed column values.
* @param {string} line Markdown table line.
* @returns {string[]} The trimmed column values.
*/
function splitLine(line) {
return line.split('|').map(x => x.trim()).filter((x, i, a) => { return x.length > 0 || [0, a.length].indexOf(i) === -1})
}

/**
* HTML table creation helper class.
* Constructs the table and returns the HTML code.
*/
function HTMLTable() {
this.ths = [];
this.tds = [];
this.alignments = [];

this.getHTMLString = function() {
let newline = '\n';
return "<table>" + newline +
this.ths.map((x) => { return this.getRow(x, 'th'); }, this).join(newline) + newline +
this.tds.map((x) => { return this.getRow(x, 'td'); }, this).join(newline) + newline +
"</table>"
};

this.getHTML = function() {
return '<table class="table">' +
this.ths.map((x, index) => { return this.getRow(x, 'th'); }, this).join('') +
this.tds.map((x, index) => { return this.getRow(x, 'td'); }, this).join('') +
'</table>'
};

this.getRow = function(vals, tag) {
return "<tr>" + vals.map((x, index) => { return "<" + tag + getStyleAttribute(this.getAlignment(index)) + ">" + x + "</" + tag + ">"}).join('') + "</tr>";
};

this.addRow = function(vals, isHeader) {
if (isHeader) {
this.ths.push(vals);
}
else {
this.tds.push(vals);
}
};

this.setAlignments = function(alignments) {
this.alignments = alignments;
};

this.getAlignment = function(colIndex) {
if (this.alignments.length <= colIndex) return alignments[0];
return this.alignments[colIndex];
}
}
4 changes: 4 additions & 0 deletions src/tailwindcss.css
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,10 @@ video {
display: flex;
}

.table {
display: table;
}

.hidden {
display: none;
}
Expand Down

0 comments on commit 11180b6

Please sign in to comment.