mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	markup: improve code block readability and isolate copy button (#34009)
Fix #33197 Improve the rendering of code blocks in markdown content for better readability and UI stability across screen sizes. Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -86,20 +86,15 @@ func (r *GlodmarkRender) highlightingRenderer(w util.BufWriter, c highlighting.C | |||||||
| 			preClasses += " is-loading" | 			preClasses += " is-loading" | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		err := r.ctx.RenderInternal.FormatWithSafeAttrs(w, `<pre class="%s">`, preClasses) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// include language-x class as part of commonmark spec, "chroma" class is used to highlight the code | 		// include language-x class as part of commonmark spec, "chroma" class is used to highlight the code | ||||||
| 		// the "display" class is used by "js/markup/math.ts" to render the code element as a block | 		// the "display" class is used by "js/markup/math.ts" to render the code element as a block | ||||||
| 		// the "math.ts" strictly depends on the structure: <pre class="code-block is-loading"><code class="language-math display">...</code></pre> | 		// the "math.ts" strictly depends on the structure: <pre class="code-block is-loading"><code class="language-math display">...</code></pre> | ||||||
| 		err = r.ctx.RenderInternal.FormatWithSafeAttrs(w, `<code class="chroma language-%s display">`, languageStr) | 		err := r.ctx.RenderInternal.FormatWithSafeAttrs(w, `<div class="code-block-container code-overflow-scroll"><pre class="%s"><code class="chroma language-%s display">`, preClasses, languageStr) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		_, err := w.WriteString("</code></pre>") | 		_, err := w.WriteString("</code></pre></div>") | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|   | |||||||
							
								
								
									
										71
									
								
								templates/devtest/markup-render.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								templates/devtest/markup-render.tmpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | {{template "devtest/devtest-header"}} | ||||||
|  | <div class="page-content devtest ui container"> | ||||||
|  | 	{{$longCode := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}} | ||||||
|  | 	<div class="tw-flex"> | ||||||
|  | 		<div class="tw-w-[50%] tw-p-4"> | ||||||
|  | 			<div class="markup render-content"> | ||||||
|  | 				Inline <code>code</code> content | ||||||
|  | 			</div> | ||||||
|  |  | ||||||
|  | 			<div class="divider"></div> | ||||||
|  |  | ||||||
|  | 			<div class="markup render-content"> | ||||||
|  | 				<p>content before</p> | ||||||
|  | 				<pre><code>Very long line with no code block or container: {{$longCode}}</code></pre> | ||||||
|  | 				<p>content after</p> | ||||||
|  | 			</div> | ||||||
|  |  | ||||||
|  | 			<div class="divider"></div> | ||||||
|  |  | ||||||
|  | 			<div class="markup render-content"> | ||||||
|  | 				<p>content before</p> | ||||||
|  | 				<div class="code-block-container code-overflow-wrap"> | ||||||
|  | 					<pre class="code-block"><code>Very long line with wrap: {{$longCode}}</code></pre> | ||||||
|  | 				</div> | ||||||
|  | 				<p>content after</p> | ||||||
|  | 			</div> | ||||||
|  |  | ||||||
|  | 			<div class="divider"></div> | ||||||
|  |  | ||||||
|  | 			<div class="markup render-content"> | ||||||
|  | 				<p>content before</p> | ||||||
|  | 				<div class="code-block-container code-overflow-scroll"> | ||||||
|  | 					<pre class="code-block"><code>Short line in scroll container</code></pre> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="code-block-container code-overflow-scroll"> | ||||||
|  | 					<pre class="code-block"><code>Very long line with scroll: {{$longCode}}</code></pre> | ||||||
|  | 				</div> | ||||||
|  | 				<p>content after</p> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  |  | ||||||
|  | 		<div class="tw-w-[50%] tw-p-4"> | ||||||
|  | 			<div class="markup render-content"> | ||||||
|  | 				<p>content before</p> | ||||||
|  | 				<div class="code-block-container"> | ||||||
|  | 					<pre class="code-block"><code class="language-math"> | ||||||
|  | 	\lim\limits_{n\rightarrow\infty}{\left(1+\frac{1}{n}\right)^n} | ||||||
|  | 					</code></pre> | ||||||
|  | 				</div> | ||||||
|  | 				<p>content after</p> | ||||||
|  | 			</div> | ||||||
|  |  | ||||||
|  | 			<div class="divider"></div> | ||||||
|  |  | ||||||
|  | 			<div class="markup render-content"> | ||||||
|  | 				<p>content before</p> | ||||||
|  | 				<div class="code-block-container"> | ||||||
|  | 					<pre class="code-block"><code class="language-mermaid is-loading"> | ||||||
|  | 	graph LR | ||||||
|  | 			A[Square Rect] -- Link text --> B((Circle)) | ||||||
|  | 			A --> C(Round Rect) | ||||||
|  | 			B --> D{Rhombus} | ||||||
|  | 			C --> D | ||||||
|  | 					</code></pre> | ||||||
|  | 				</div> | ||||||
|  | 				<p>content after</p> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  | {{template "devtest/devtest-footer"}} | ||||||
| @@ -1,8 +1,3 @@ | |||||||
| .markup .code-block, |  | ||||||
| .markup .mermaid-block { |  | ||||||
|   position: relative; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .markup .code-copy { | .markup .code-copy { | ||||||
|   position: absolute; |   position: absolute; | ||||||
|   top: 8px; |   top: 8px; | ||||||
| @@ -28,8 +23,8 @@ | |||||||
|   background: var(--color-secondary-dark-1) !important; |   background: var(--color-secondary-dark-1) !important; | ||||||
| } | } | ||||||
|  |  | ||||||
| .markup .code-block:hover .code-copy, | .markup .code-block-container:hover .code-copy, | ||||||
| .markup .mermaid-block:hover .code-copy { | .markup .code-block:hover .code-copy { | ||||||
|   visibility: visible; |   visibility: visible; | ||||||
|   animation: fadein 0.2s both; |   animation: fadein 0.2s both; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -443,13 +443,25 @@ | |||||||
| } | } | ||||||
|  |  | ||||||
| .markup pre > code { | .markup pre > code { | ||||||
|   padding: 0; |  | ||||||
|   margin: 0; |  | ||||||
|   font-size: 100%; |   font-size: 100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .markup .code-block, | ||||||
|  | .markup .code-block-container { | ||||||
|  |   position: relative; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .markup .code-block-container.code-overflow-wrap pre > code { | ||||||
|   white-space: pre-wrap; |   white-space: pre-wrap; | ||||||
|   overflow-wrap: anywhere; | } | ||||||
|   background: transparent; |  | ||||||
|   border: 0; | .markup .code-block-container.code-overflow-scroll pre { | ||||||
|  |   overflow-x: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .markup .code-block-container.code-overflow-scroll pre > code { | ||||||
|  |   white-space: pre; | ||||||
|  |   overflow-wrap: normal; | ||||||
| } | } | ||||||
|  |  | ||||||
| .markup .highlight { | .markup .highlight { | ||||||
| @@ -470,16 +482,11 @@ | |||||||
|   word-break: normal; |   word-break: normal; | ||||||
| } | } | ||||||
|  |  | ||||||
| .markup pre { |  | ||||||
|   word-wrap: normal; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .markup pre code, | .markup pre code, | ||||||
| .markup pre tt { | .markup pre tt { | ||||||
|   display: inline; |   display: inline; | ||||||
|   padding: 0; |   padding: 0; | ||||||
|   line-height: inherit; |   line-height: inherit; | ||||||
|   word-wrap: normal; |  | ||||||
|   background-color: transparent; |   background-color: transparent; | ||||||
|   border: 0; |   border: 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,6 +15,8 @@ export function initMarkupCodeCopy(elMarkup: HTMLElement): void { | |||||||
|     const btn = makeCodeCopyButton(); |     const btn = makeCodeCopyButton(); | ||||||
|     // remove final trailing newline introduced during HTML rendering |     // remove final trailing newline introduced during HTML rendering | ||||||
|     btn.setAttribute('data-clipboard-text', el.textContent.replace(/\r?\n$/, '')); |     btn.setAttribute('data-clipboard-text', el.textContent.replace(/\r?\n$/, '')); | ||||||
|     el.after(btn); |     // we only want to use `.code-block-container` if it exists, no matter `.code-block` exists or not. | ||||||
|  |     const btnContainer = el.closest('.code-block-container') ?? el.closest('.code-block'); | ||||||
|  |     btnContainer.append(btn); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 D
					D