Skip to content

Commit c8ef5eb

Browse files
committed
feat: Enhance frontmatter rendering with collapsible details and smart formatting (#8394)
1 parent f8911df commit c8ef5eb

2 files changed

Lines changed: 58 additions & 16 deletions

File tree

resources/scss/src/component/Markdown.scss

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,7 @@
117117
display: none;
118118
}
119119

120-
.neo-frontmatter-table {
121-
margin-bottom: 20px;
122-
width : fit-content;
123-
124-
td {
125-
padding: 4px 10px;
126-
}
127-
128-
td:first-child {
129-
font-weight: bold;
130-
}
131-
}
132-
120+
.neo-frontmatter-table,
133121
> table {
134122
border : 1px solid lightgray;
135123
border-collapse: separate;
@@ -160,4 +148,17 @@
160148
font-weight : bold;
161149
}
162150
}
151+
152+
.neo-frontmatter-table {
153+
margin-bottom: 20px;
154+
width : fit-content;
155+
156+
td {
157+
padding: 4px 10px;
158+
}
159+
160+
td:first-child {
161+
font-weight: bold;
162+
}
163+
}
163164
}

src/component/Markdown.mjs

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,17 @@ class Markdown extends Component {
4444
*/
4545
baseCls: ['neo-markdown-component'],
4646
/**
47+
* True to parse and render YAML frontmatter (metadata) at the top of the content.
48+
* Useful for displaying file metadata like title, date, or tags.
4749
* @member {Boolean} renderFrontmatter=true
4850
*/
4951
renderFrontmatter: true,
52+
/**
53+
* True to wrap the rendered frontmatter table in a collapsible <details> tag.
54+
* This keeps the metadata accessible but unobtrusive, collapsed by default.
55+
* @member {Boolean} useFrontmatterDetails=true
56+
*/
57+
useFrontmatterDetails: true,
5058
/**
5159
* @member {String|null} value_=null
5260
* @reactive
@@ -139,19 +147,52 @@ class Markdown extends Component {
139147
return inputString
140148
}
141149

150+
/**
151+
* @param {*} value
152+
* @returns {String}
153+
*/
154+
formatFrontMatterValue(value) {
155+
if (Array.isArray(value)) {
156+
return value.join(', ')
157+
}
158+
159+
if (typeof value === 'boolean') {
160+
return `<i class="fa-solid fa-${value ? 'check' : 'xmark'}"></i>`
161+
}
162+
163+
if (typeof value === 'string') {
164+
// ISO Date
165+
if (/^\d{4}-\d{2}-\d{2}T/.test(value)) {
166+
return new Date(value).toLocaleString()
167+
}
168+
169+
// URL
170+
if (/^https?:\/\//.test(value)) {
171+
return `<a href="${value}" target="_blank">${value}</a>`
172+
}
173+
}
174+
175+
return value
176+
}
177+
142178
/**
143179
* @param {Object} data
144180
* @returns {String}
145181
*/
146182
frontMatterToHtml(data) {
147-
let html = '<table class="neo-frontmatter-table"><tbody>';
183+
let me = this,
184+
html = '<table class="neo-frontmatter-table"><tbody>';
148185

149186
Object.entries(data).forEach(([key, value]) => {
150-
html += `<tr><td>${key}</td><td>${value}</td></tr>`
187+
html += `<tr><td>${key}</td><td>${me.formatFrontMatterValue(value)}</td></tr>`
151188
});
152189

153190
html += '</tbody></table>';
154191

192+
if (me.useFrontmatterDetails) {
193+
return `<details><summary>Frontmatter</summary>${html}</details>`
194+
}
195+
155196
return html
156197
}
157198

@@ -171,7 +212,7 @@ class Markdown extends Component {
171212
}
172213

173214
try {
174-
return me.frontMatterToHtml(me.parseFrontMatter(frontmatter))
215+
return me.frontMatterToHtml(me.parseFrontMatter(frontmatter)) + '\n'
175216
} catch (e) {
176217
console.error('Error parsing FrontMatter', e);
177218
return match

0 commit comments

Comments
 (0)