@@ -18,35 +18,78 @@ export default function MarkdownPreview() {
1818 } ;
1919
2020 const convertMarkdownToHTML = ( markdown : string ) : string => {
21- return markdown
22- // Headers
23- . replace ( / ^ # # # ( .* $ ) / gim, '<h3>$1</h3>' )
24- . replace ( / ^ # # ( .* $ ) / gim, '<h2>$1</h2>' )
25- . replace ( / ^ # ( .* $ ) / gim, '<h1>$1</h1>' )
26- // Bold
27- . replace ( / \* \* ( .* ?) \* \* / g, '<strong>$1</strong>' )
28- . replace ( / _ _ ( .* ?) _ _ / g, '<strong>$1</strong>' )
29- // Italic
30- . replace ( / \* ( .* ?) \* / g, '<em>$1</em>' )
31- . replace ( / _ ( .* ?) _ / g, '<em>$1</em>' )
32- // Code inline
33- . replace ( / ` ( .* ?) ` / g, '<code>$1</code>' )
34- // Code blocks
35- . replace ( / ` ` ` ( [ \s \S ] * ?) ` ` ` / g, '<pre><code>$1</code></pre>' )
36- // Links
37- . replace ( / \[ ( [ ^ \] ] + ) \] \( ( [ ^ ) ] + ) \) / g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>' )
38- // Images
39- . replace ( / ! \[ ( [ ^ \] ] * ) \] \( ( [ ^ ) ] + ) \) / g, '<img src="$2" alt="$1" style="max-width: 100%; height: auto;" />' )
40- // Lists
41- . replace ( / ^ \* ( .* $ ) / gim, '<ul><li>$1</li></ul>' )
42- . replace ( / ^ \- ( .* $ ) / gim, '<ul><li>$1</li></ul>' )
43- . replace ( / ^ \d + \. ( .* $ ) / gim, '<ol><li>$1</li></ol>' )
44- // Blockquotes
45- . replace ( / ^ > ( .* $ ) / gim, '<blockquote>$1</blockquote>' )
46- // Horizontal rules
47- . replace ( / ^ - - - $ / gim, '<hr>' )
48- // Line breaks
49- . replace ( / \n / g, '<br>' ) ;
21+ // Split into lines for better processing
22+ const lines = markdown . split ( '\n' ) ;
23+ const processedLines : string [ ] = [ ] ;
24+
25+ for ( let i = 0 ; i < lines . length ; i ++ ) {
26+ const line = lines [ i ] ;
27+ let processedLine = line ;
28+
29+ // Process inline formatting first
30+ processedLine = processedLine
31+ // Bold
32+ . replace ( / \* \* ( .* ?) \* \* / g, '<strong>$1</strong>' )
33+ . replace ( / _ _ ( .* ?) _ _ / g, '<strong>$1</strong>' )
34+ // Italic
35+ . replace ( / \* ( .* ?) \* / g, '<em>$1</em>' )
36+ . replace ( / _ ( .* ?) _ / g, '<em>$1</em>' )
37+ // Code inline
38+ . replace ( / ` ( .* ?) ` / g, '<code>$1</code>' )
39+ // Links
40+ . replace ( / \[ ( [ ^ \] ] + ) \] \( ( [ ^ ) ] + ) \) / g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>' )
41+ // Images
42+ . replace ( / ! \[ ( [ ^ \] ] * ) \] \( ( [ ^ ) ] + ) \) / g, '<img src="$2" alt="$1" style="max-width: 100%; height: auto;" />' ) ;
43+
44+ // Process block elements
45+ if ( line . match ( / ^ # # # ( .* $ ) / ) ) {
46+ processedLine = `<h3>${ line . replace ( / ^ # # # / , '' ) } </h3>` ;
47+ } else if ( line . match ( / ^ # # ( .* $ ) / ) ) {
48+ processedLine = `<h2>${ line . replace ( / ^ # # / , '' ) } </h2>` ;
49+ } else if ( line . match ( / ^ # ( .* $ ) / ) ) {
50+ processedLine = `<h1>${ line . replace ( / ^ # / , '' ) } </h1>` ;
51+ } else if ( line . match ( / ^ > ( .* $ ) / ) ) {
52+ processedLine = `<blockquote>${ line . replace ( / ^ > / , '' ) } </blockquote>` ;
53+ } else if ( line . match ( / ^ - - - $ / ) ) {
54+ processedLine = '<hr>' ;
55+ } else if ( line . match ( / ^ \* ( .* $ ) / ) || line . match ( / ^ \- ( .* $ ) / ) ) {
56+ processedLine = `<li>${ line . replace ( / ^ [ \* \- ] / , '' ) } </li>` ;
57+ } else if ( line . match ( / ^ \d + \. ( .* $ ) / ) ) {
58+ processedLine = `<li>${ line . replace ( / ^ \d + \. / , '' ) } </li>` ;
59+ } else if ( line . trim ( ) === '' ) {
60+ // Empty lines become paragraph breaks
61+ processedLine = '</p><p>' ;
62+ } else {
63+ // Regular text lines
64+ processedLine = processedLine ;
65+ }
66+
67+ processedLines . push ( processedLine ) ;
68+ }
69+
70+ // Join lines and handle special cases
71+ let result = processedLines . join ( '\n' ) ;
72+
73+ // Handle code blocks (multi-line)
74+ result = result . replace ( / ` ` ` ( [ \s \S ] * ?) ` ` ` / g, '<pre><code>$1</code></pre>' ) ;
75+
76+ // Handle lists properly
77+ result = result . replace ( / ( < l i > .* < \/ l i > ) / g, ( match ) => {
78+ // Check if it's a numbered list or bullet list
79+ const isNumbered = match . includes ( '<li>' ) && / ^ \d + \. / . test ( match ) ;
80+ const listType = isNumbered ? 'ol' : 'ul' ;
81+ return `<${ listType } >${ match } </${ listType } >` ;
82+ } ) ;
83+
84+ // Wrap in paragraphs and clean up
85+ result = result
86+ . replace ( / ^ (? ! < [ h o u ] [ 1 - 6 l r ] | < p > | < b l o c k q u o t e > | < p r e > | < h r > ) ( .+ ) $ / gm, '<p>$1</p>' )
87+ . replace ( / < \/ p > \s * < p > / g, '</p><p>' )
88+ . replace ( / < p > < \/ p > / g, '' ) // Remove empty paragraphs
89+ . replace ( / < p > ( < [ h o u ] [ 1 - 6 l r ] | < b l o c k q u o t e > | < p r e > | < h r > ) / g, '$1' ) // Remove p tags around block elements
90+ . replace ( / ( < \/ [ h o u ] [ 1 - 6 l r ] | < \/ b l o c k q u o t e > | < \/ p r e > | < \/ h r > ) < \/ p > / g, '$1' ) ; // Remove closing p tags around block elements
91+
92+ return result ;
5093 } ;
5194
5295 const clearAll = ( ) => {
0 commit comments