@@ -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 = / ^ \[ ! ( N O T E | T I P | I M P O R T A N T | W A R N I N G | C A U T I O N ) \] (?: \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" ;
0 commit comments