Skip to content

Commit f8b70ec

Browse files
Merge pull request #52 from ThisIs-Developer/copilot/add-support-for-admonitions
Add GitHub-style alert/admonition rendering for NOTE/TIP/IMPORTANT/WARNING/CAUTION
2 parents 6ae149a + 60981e9 commit f8b70ec

3 files changed

Lines changed: 222 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Inside the **zoom modal** you can:
8585
- Tables
8686
- Code blocks with syntax highlighting
8787
- Blockquotes
88+
- GitHub-style alerts/admonitions (`[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, `[!CAUTION]`)
8889
- Horizontal rules
8990
- Task lists
9091
- LaTeX equations (inline and block)

script.js

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,90 @@ document.addEventListener("DOMContentLoaded", function () {
136136
renderer: renderer,
137137
});
138138

139+
const GITHUB_ALERT_META = {
140+
note: {
141+
label: "Note",
142+
viewBox: "0 0 512 512",
143+
path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336l24 0 0-64-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l48 0c13.3 0 24 10.7 24 24l0 88 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z",
144+
},
145+
tip: {
146+
label: "Tip",
147+
viewBox: "0 0 384 512",
148+
path: "M297.2 248.9C311.6 228.3 320 203.2 320 176c0-70.7-57.3-128-128-128S64 105.3 64 176c0 27.2 8.4 52.3 22.8 72.9c3.7 5.3 8.1 11.3 12.8 17.7c0 0 0 0 0 0c12.9 17.7 28.3 38.9 39.8 59.8c10.4 19 15.7 38.8 18.3 57.5L109 384c-2.2-12-5.9-23.7-11.8-34.5c-9.9-18-22.2-34.9-34.5-51.8c0 0 0 0 0 0s0 0 0 0c-5.2-7.1-10.4-14.2-15.4-21.4C27.6 247.9 16 213.3 16 176C16 78.8 94.8 0 192 0s176 78.8 176 176c0 37.3-11.6 71.9-31.4 100.3c-5 7.2-10.2 14.3-15.4 21.4c0 0 0 0 0 0s0 0 0 0c-12.3 16.8-24.6 33.7-34.5 51.8c-5.9 10.8-9.6 22.5-11.8 34.5l-48.6 0c2.6-18.7 7.9-38.6 18.3-57.5c11.5-20.9 26.9-42.1 39.8-59.8c0 0 0 0 0 0s0 0 0 0s0 0 0 0c4.7-6.4 9-12.4 12.7-17.7zM192 128c-26.5 0-48 21.5-48 48c0 8.8-7.2 16-16 16s-16-7.2-16-16c0-44.2 35.8-80 80-80c8.8 0 16 7.2 16 16s-7.2 16-16 16zm0 384c-44.2 0-80-35.8-80-80l0-16 160 0 0 16c0 44.2-35.8 80-80 80z",
149+
},
150+
important: {
151+
label: "Important",
152+
viewBox: "0 0 512 512",
153+
path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-384c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z",
154+
},
155+
warning: {
156+
label: "Warning",
157+
viewBox: "0 0 512 512",
158+
path: "M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z",
159+
},
160+
caution: {
161+
label: "Caution",
162+
viewBox: "0 0 512 512",
163+
path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z",
164+
},
165+
};
166+
const GITHUB_ALERT_MARKER_REGEX = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\](?:\s+|$)/i;
167+
168+
function enhanceGitHubAlerts(container) {
169+
if (!container) return;
170+
171+
const blockquotes = container.querySelectorAll("blockquote");
172+
blockquotes.forEach((blockquote) => {
173+
let firstParagraph = null;
174+
for (const child of blockquote.children) {
175+
if (child.tagName === "P") {
176+
firstParagraph = child;
177+
break;
178+
}
179+
}
180+
if (!firstParagraph) return;
181+
182+
const firstParagraphHtml = firstParagraph.innerHTML.trim();
183+
const markerMatch = firstParagraphHtml.match(GITHUB_ALERT_MARKER_REGEX);
184+
if (!markerMatch) return;
185+
186+
const alertType = markerMatch[1].toLowerCase();
187+
blockquote.classList.add("markdown-alert", `markdown-alert-${alertType}`);
188+
189+
const title = document.createElement("p");
190+
title.className = "markdown-alert-title";
191+
const alertMeta = GITHUB_ALERT_META[alertType] || { label: markerMatch[1], path: "" };
192+
const icon = document.createElement("span");
193+
icon.className = "markdown-alert-icon";
194+
icon.setAttribute("aria-hidden", "true");
195+
196+
if (alertMeta.path) {
197+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
198+
svg.setAttribute("viewBox", alertMeta.viewBox || "0 0 512 512");
199+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
200+
path.setAttribute("d", alertMeta.path);
201+
svg.appendChild(path);
202+
icon.appendChild(svg);
203+
}
204+
205+
const label = document.createElement("span");
206+
label.textContent = alertMeta.label;
207+
title.appendChild(icon);
208+
title.appendChild(label);
209+
210+
blockquote.insertBefore(title, blockquote.firstChild);
211+
212+
const remainingHtml = firstParagraphHtml
213+
.replace(GITHUB_ALERT_MARKER_REGEX, "")
214+
.trim();
215+
if (remainingHtml) {
216+
firstParagraph.innerHTML = remainingHtml;
217+
} else {
218+
firstParagraph.remove();
219+
}
220+
});
221+
}
222+
139223
const sampleMarkdown = `# Welcome to Markdown Viewer
140224
141225
## ✨ Key Features
@@ -776,6 +860,7 @@ This is a fully client-side application. Your content never leaves your browser
776860
ADD_ATTR: ['id', 'class', 'style']
777861
});
778862
markdownPreview.innerHTML = sanitizedHtml;
863+
enhanceGitHubAlerts(markdownPreview);
779864

780865
processEmojis(markdownPreview);
781866

@@ -1729,6 +1814,10 @@ This is a fully client-side application. Your content never leaves your browser
17291814
ADD_TAGS: ['mjx-container'],
17301815
ADD_ATTR: ['id', 'class', 'style']
17311816
});
1817+
const tempContainer = document.createElement("div");
1818+
tempContainer.innerHTML = sanitizedHtml;
1819+
enhanceGitHubAlerts(tempContainer);
1820+
const enhancedHtml = tempContainer.innerHTML;
17321821
const isDarkTheme =
17331822
document.documentElement.getAttribute("data-theme") === "dark";
17341823
const cssTheme = isDarkTheme
@@ -1772,6 +1861,40 @@ This is a fully client-side application. Your content never leaves your browser
17721861
.hljs-addition { color: ${isDarkTheme ? "#aff5b4" : "#22863a"}; background-color: ${isDarkTheme ? "#033a16" : "#f0fff4"}; }
17731862
.hljs-deletion { color: ${isDarkTheme ? "#ffdcd7" : "#b31d28"}; background-color: ${isDarkTheme ? "#67060c" : "#ffeef0"}; }
17741863
1864+
.markdown-alert {
1865+
padding: 0.5rem 1rem;
1866+
margin-bottom: 16px;
1867+
border-left: 0.25em solid;
1868+
border-radius: 0.375rem;
1869+
}
1870+
.markdown-alert > :last-child {
1871+
margin-bottom: 0;
1872+
}
1873+
.markdown-alert-title {
1874+
margin: 0 0 8px;
1875+
font-weight: 600;
1876+
line-height: 1.25;
1877+
display: flex;
1878+
align-items: center;
1879+
gap: 8px;
1880+
}
1881+
.markdown-alert-icon {
1882+
display: inline-flex;
1883+
width: 16px;
1884+
height: 16px;
1885+
}
1886+
.markdown-alert-icon svg {
1887+
width: 16px;
1888+
height: 16px;
1889+
fill: currentColor;
1890+
}
1891+
.markdown-alert-note { color: ${isDarkTheme ? "#4493f8" : "#0969da"}; border-left-color: ${isDarkTheme ? "#4493f8" : "#0969da"}; background-color: ${isDarkTheme ? "rgba(31, 111, 235, 0.15)" : "#ddf4ff"}; }
1892+
.markdown-alert-tip { color: ${isDarkTheme ? "#3fb950" : "#1a7f37"}; border-left-color: ${isDarkTheme ? "#3fb950" : "#1a7f37"}; background-color: ${isDarkTheme ? "rgba(35, 134, 54, 0.15)" : "#dafbe1"}; }
1893+
.markdown-alert-important { color: ${isDarkTheme ? "#ab7df8" : "#8250df"}; border-left-color: ${isDarkTheme ? "#ab7df8" : "#8250df"}; background-color: ${isDarkTheme ? "rgba(137, 87, 229, 0.15)" : "#fbefff"}; }
1894+
.markdown-alert-warning { color: ${isDarkTheme ? "#d29922" : "#9a6700"}; border-left-color: ${isDarkTheme ? "#d29922" : "#9a6700"}; background-color: ${isDarkTheme ? "rgba(210, 153, 34, 0.18)" : "#fff8c5"}; }
1895+
.markdown-alert-caution { color: ${isDarkTheme ? "#f85149" : "#cf222e"}; border-left-color: ${isDarkTheme ? "#f85149" : "#cf222e"}; background-color: ${isDarkTheme ? "rgba(248, 81, 73, 0.18)" : "#ffebe9"}; }
1896+
.markdown-alert > *:not(.markdown-alert-title) { color: ${isDarkTheme ? "#c9d1d9" : "#24292e"}; }
1897+
17751898
@media (max-width: 767px) {
17761899
.markdown-body {
17771900
padding: 15px;
@@ -1781,7 +1904,7 @@ This is a fully client-side application. Your content never leaves your browser
17811904
</head>
17821905
<body>
17831906
<article class="markdown-body">
1784-
${sanitizedHtml}
1907+
${enhancedHtml}
17851908
</article>
17861909
</body>
17871910
</html>`;
@@ -2294,6 +2417,7 @@ This is a fully client-side application. Your content never leaves your browser
22942417
const tempElement = document.createElement("div");
22952418
tempElement.className = "markdown-body pdf-export";
22962419
tempElement.innerHTML = sanitizedHtml;
2420+
enhanceGitHubAlerts(tempElement);
22972421
tempElement.style.padding = "20px";
22982422
tempElement.style.width = "210mm";
22992423
tempElement.style.margin = "0 auto";

styles.css

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,102 @@ body {
175175
padding: 0.2em 0.4em;
176176
}
177177

178+
.markdown-body .markdown-alert {
179+
padding: 0.5rem 1rem;
180+
margin-bottom: 16px;
181+
border-left: 0.25em solid;
182+
border-radius: 0.375rem;
183+
}
184+
185+
.markdown-body .markdown-alert > :last-child {
186+
margin-bottom: 0;
187+
}
188+
189+
.markdown-body .markdown-alert-title {
190+
margin: 0 0 8px;
191+
font-weight: 600;
192+
line-height: 1.25;
193+
display: flex;
194+
align-items: center;
195+
gap: 8px;
196+
}
197+
198+
.markdown-body .markdown-alert-icon {
199+
display: inline-flex;
200+
width: 16px;
201+
height: 16px;
202+
}
203+
204+
.markdown-body .markdown-alert-icon svg {
205+
width: 16px;
206+
height: 16px;
207+
fill: currentColor;
208+
}
209+
210+
.markdown-body .markdown-alert-note {
211+
color: #0969da;
212+
border-left-color: #0969da;
213+
background-color: #ddf4ff;
214+
}
215+
216+
.markdown-body .markdown-alert-tip {
217+
color: #1a7f37;
218+
border-left-color: #1a7f37;
219+
background-color: #dafbe1;
220+
}
221+
222+
.markdown-body .markdown-alert-important {
223+
color: #8250df;
224+
border-left-color: #8250df;
225+
background-color: #fbefff;
226+
}
227+
228+
.markdown-body .markdown-alert-warning {
229+
color: #9a6700;
230+
border-left-color: #9a6700;
231+
background-color: #fff8c5;
232+
}
233+
234+
.markdown-body .markdown-alert-caution {
235+
color: #cf222e;
236+
border-left-color: #cf222e;
237+
background-color: #ffebe9;
238+
}
239+
240+
.markdown-body .markdown-alert > *:not(.markdown-alert-title) {
241+
color: var(--preview-text-color);
242+
}
243+
244+
[data-theme="dark"] .markdown-body .markdown-alert-note {
245+
color: #4493f8;
246+
background-color: rgba(31, 111, 235, 0.15);
247+
border-left-color: #4493f8;
248+
}
249+
250+
[data-theme="dark"] .markdown-body .markdown-alert-tip {
251+
color: #3fb950;
252+
background-color: rgba(35, 134, 54, 0.15);
253+
border-left-color: #3fb950;
254+
}
255+
256+
[data-theme="dark"] .markdown-body .markdown-alert-important {
257+
color: #ab7df8;
258+
background-color: rgba(137, 87, 229, 0.15);
259+
border-left-color: #ab7df8;
260+
}
261+
262+
[data-theme="dark"] .markdown-body .markdown-alert-warning {
263+
color: #d29922;
264+
background-color: rgba(210, 153, 34, 0.18);
265+
border-left-color: #d29922;
266+
}
267+
268+
[data-theme="dark"] .markdown-body .markdown-alert-caution {
269+
color: #f85149;
270+
background-color: rgba(248, 81, 73, 0.18);
271+
border-left-color: #f85149;
272+
}
273+
178274
.toolbar {
179275
display: flex;
180276
gap: 8px;

0 commit comments

Comments
 (0)