Add a Description field to the Guide information dialog

Reuses the guide's existing descriptionHtml/descriptionText, which
already renders on the PDF cover and at the top of every other export
format, so it surfaces alongside author/co-authors/organization with
no exporter changes needed.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
2026-06-15 13:04:35 -05:00
co-authored by Claude Sonnet 4.6
parent 0b490e2aa9
commit 722c5d2eee
3 changed files with 35 additions and 4 deletions
+18
View File
@@ -187,3 +187,21 @@ function fmtDate(iso) {
const escapeHtml = (s) => String(s ?? '')
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
/** Inverse of textToHtml, for loading sanitized description HTML into a plain textarea. */
function htmlToPlainText(html) {
return String(html || '')
.replace(/<(br|\/p|\/div|\/li|\/h[1-6])\s*\/?>/gi, '\n')
.replace(/<[^>]*>/g, '')
.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, '\'').replace(/&amp;/g, '&')
.replace(/[ \t]+/g, ' ').replace(/\s*\n\s*/g, '\n').trim();
}
/** Plain textarea text -> sanitizer-allowed paragraph HTML (blank line = new paragraph). */
function textToHtml(text) {
const trimmed = String(text || '').trim();
if (!trimmed) return '';
return trimmed.split(/\n{2,}/)
.map((para) => `<p>${escapeHtml(para).replace(/\n/g, '<br>')}</p>`)
.join('');
}