Skip to content

markup: improve code block readability and isolate copy button #34009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 19, 2025
Merged
9 changes: 2 additions & 7 deletions modules/markup/markdown/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,15 @@ func (r *GlodmarkRender) highlightingRenderer(w util.BufWriter, c highlighting.C
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
// 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>
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 {
return
}
} else {
_, err := w.WriteString("</code></pre>")
_, err := w.WriteString("</code></pre></div>")
if err != nil {
return
}
Expand Down
71 changes: 71 additions & 0 deletions templates/devtest/markup-render.tmpl
Original file line number Diff line number Diff line change
@@ -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"}}
9 changes: 2 additions & 7 deletions web_src/css/markup/codecopy.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
.markup .code-block,
.markup .mermaid-block {
position: relative;
}

.markup .code-copy {
position: absolute;
top: 8px;
Expand All @@ -28,8 +23,8 @@
background: var(--color-secondary-dark-1) !important;
}

.markup .code-block:hover .code-copy,
.markup .mermaid-block:hover .code-copy {
.markup .code-block-container:hover .code-copy,
.markup .code-block:hover .code-copy {
visibility: visible;
animation: fadein 0.2s both;
}
27 changes: 17 additions & 10 deletions web_src/css/markup/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,25 @@
}

.markup pre > code {
padding: 0;
margin: 0;
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;
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 {
Expand All @@ -470,16 +482,11 @@
word-break: normal;
}

.markup pre {
word-wrap: normal;
}

.markup pre code,
.markup pre tt {
display: inline;
padding: 0;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
Expand Down
4 changes: 3 additions & 1 deletion web_src/js/markup/codecopy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export function initMarkupCodeCopy(elMarkup: HTMLElement): void {
const btn = makeCodeCopyButton();
// remove final trailing newline introduced during HTML rendering
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);
});
}