Merge pull request #2656 from ZhenShuo2021/feat/codeblock-title

 Feat: support title in code block
This commit is contained in:
Nuno C.
2025-12-22 17:11:53 +00:00
committed by GitHub
9 changed files with 91 additions and 110 deletions
+29 -8
View File
@@ -3323,13 +3323,37 @@
} }
} }
@layer utilities { @layer utilities {
.prose .chroma { .highlight-wrapper {
position: static; position: relative;
z-index: 0;
display: block;
overflow: hidden;
border-radius: var(--radius-md); border-radius: var(--radius-md);
}
.prose .highlight:not(:has(table)) .chroma, .prose .highlight > .chroma {
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
margin-top: 1.7142857em;
margin-bottom: 1.7142857em;
}
.highlight-wrapper pre, .highlight-wrapper table, .highlight-wrapper div {
margin-top: 0;
margin-bottom: 0;
}
.highlight-wrapper:has(.codeblock-title) pre {
border-radius: 0;
}
.codeblock-title {
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
border-color: rgba(var(--color-neutral-200), 1);
padding-inline: calc(var(--spacing) * 4);
padding-block: calc(var(--spacing) * 2);
&:is(.dark *) {
border-color: rgba(var(--color-neutral-800), 1);
}
background-color: #fff;
&:is(.dark *) {
background-color: #0d1117;
}
} }
.chroma .lntd, .chroma .lntd pre { .chroma .lntd, .chroma .lntd pre {
margin: calc(var(--spacing) * 0); margin: calc(var(--spacing) * 0);
@@ -4056,14 +4080,11 @@ button, [role="button"] {
margin-right: calc(var(--spacing) * 0); margin-right: calc(var(--spacing) * 0);
} }
} }
.highlight-wrapper {
display: block;
}
.highlight { .highlight {
position: relative; position: relative;
z-index: 0; z-index: 0;
} }
.highlight:hover > .copy-button { .highlight-wrapper:hover > .copy-button {
visibility: visible; visibility: visible;
} }
.copy-button { .copy-button {
+18 -6
View File
@@ -1,12 +1,24 @@
/* -- Chroma Highlight -- */ /* -- Chroma Highlight -- */
/* Background */ /* margins for codeblock title */
.prose .chroma { .highlight-wrapper {
@apply static rounded-md; @apply block relative z-0 overflow-hidden shadow rounded-md;
margin-top: 1.7142857em;
margin-bottom: 1.7142857em;
} }
.prose .highlight:not(:has(table)) .chroma, .highlight-wrapper pre,
.prose .highlight > .chroma { .highlight-wrapper table, .highlight-wrapper div {
@apply shadow; margin-top: 0;
margin-bottom: 0;
}
.highlight-wrapper:has(.codeblock-title) pre {
@apply rounded-none;
}
.codeblock-title {
@apply px-4 py-2 border-b border-neutral-200 dark:border-neutral-800;
@apply bg-white dark:bg-[#0d1117];
} }
/* LineTableTD */ /* LineTableTD */
+1 -5
View File
@@ -95,15 +95,11 @@ button,
} }
/* Code Copy */ /* Code Copy */
.highlight-wrapper {
@apply block;
}
.highlight { .highlight {
@apply relative z-0; @apply relative z-0;
} }
.highlight:hover > .copy-button { .highlight-wrapper:hover > .copy-button {
@apply visible; @apply visible;
} }
+15 -17
View File
@@ -2,31 +2,26 @@ var scriptBundle = document.getElementById("script-bundle");
var copyText = scriptBundle?.getAttribute("data-copy") || "Copy"; var copyText = scriptBundle?.getAttribute("data-copy") || "Copy";
var copiedText = scriptBundle?.getAttribute("data-copied") || "Copied"; var copiedText = scriptBundle?.getAttribute("data-copied") || "Copied";
function createCopyButton(highlightDiv) { function createCopyButton(highlightWrapper) {
const button = document.createElement("button"); const button = document.createElement("button");
button.className = "copy-button"; button.className = "copy-button";
button.type = "button"; button.type = "button";
button.ariaLabel = copyText; button.ariaLabel = copyText;
button.innerText = copyText; button.innerText = copyText;
button.addEventListener("click", () => copyCodeToClipboard(button, highlightDiv)); button.addEventListener("click", () => copyCodeToClipboard(button, highlightWrapper));
highlightWrapper.insertBefore(button, highlightWrapper.firstChild);
highlightDiv.insertBefore(button, highlightDiv.firstChild);
const wrapper = document.createElement("div");
wrapper.className = "highlight-wrapper";
highlightDiv.parentNode.insertBefore(wrapper, highlightDiv);
wrapper.appendChild(highlightDiv);
} }
async function copyCodeToClipboard(button, highlightDiv) { async function copyCodeToClipboard(button, highlightWrapper) {
const codeToCopy = getCodeText(highlightDiv); const codeToCopy = getCodeText(highlightWrapper);
function fallback(codeToCopy, highlightDiv) { function fallback(codeToCopy, highlightWrapper) {
const textArea = document.createElement("textArea"); const textArea = document.createElement("textArea");
textArea.contentEditable = "true"; textArea.contentEditable = "true";
textArea.readOnly = "false"; textArea.readOnly = "false";
textArea.className = "copy-textarea"; textArea.className = "copy-textarea";
textArea.value = codeToCopy; textArea.value = codeToCopy;
highlightDiv.insertBefore(textArea, highlightDiv.firstChild); highlightWrapper.insertBefore(textArea, highlightWrapper.firstChild);
const range = document.createRange(); const range = document.createRange();
range.selectNodeContents(textArea); range.selectNodeContents(textArea);
const sel = window.getSelection(); const sel = window.getSelection();
@@ -34,7 +29,7 @@ async function copyCodeToClipboard(button, highlightDiv) {
sel.addRange(range); sel.addRange(range);
textArea.setSelectionRange(0, 999999); textArea.setSelectionRange(0, 999999);
document.execCommand("copy"); document.execCommand("copy");
highlightDiv.removeChild(textArea); highlightWrapper.removeChild(textArea);
} }
try { try {
@@ -42,10 +37,10 @@ async function copyCodeToClipboard(button, highlightDiv) {
if (result.state == "granted" || result.state == "prompt") { if (result.state == "granted" || result.state == "prompt") {
await navigator.clipboard.writeText(codeToCopy); await navigator.clipboard.writeText(codeToCopy);
} else { } else {
fallback(codeToCopy, highlightDiv); fallback(codeToCopy, highlightWrapper);
} }
} catch (_) { } catch (_) {
fallback(codeToCopy, highlightDiv); fallback(codeToCopy, highlightWrapper);
} finally { } finally {
button.blur(); button.blur();
button.innerText = copiedText; button.innerText = copiedText;
@@ -55,7 +50,10 @@ async function copyCodeToClipboard(button, highlightDiv) {
} }
} }
function getCodeText(highlightDiv) { function getCodeText(highlightWrapper) {
const highlightDiv = highlightWrapper.querySelector(".highlight");
if (!highlightDiv) return "";
const codeBlock = highlightDiv.querySelector("code"); const codeBlock = highlightDiv.querySelector("code");
const inlineLines = codeBlock?.querySelectorAll(".cl"); // linenos=inline const inlineLines = codeBlock?.querySelectorAll(".cl"); // linenos=inline
const tableCodeCell = highlightDiv?.querySelector(".lntable .lntd:last-child code"); // linenos=table const tableCodeCell = highlightDiv?.querySelector(".lntable .lntd:last-child code"); // linenos=table
@@ -75,5 +73,5 @@ function getCodeText(highlightDiv) {
} }
window.addEventListener("DOMContentLoaded", (event) => { window.addEventListener("DOMContentLoaded", (event) => {
document.querySelectorAll(".highlight").forEach((highlightDiv) => createCopyButton(highlightDiv)); document.querySelectorAll(".highlight-wrapper").forEach((highlightWrapper) => createCopyButton(highlightWrapper));
}); });
@@ -65,7 +65,7 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
## Code Blocks ## Code Blocks
### Code block with backticks ### General code block
```html ```html
<!DOCTYPE html> <!DOCTYPE html>
@@ -80,23 +80,9 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
</html> </html>
``` ```
### Code block indented with four spaces ### Code block with title and line highlight
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example HTML5 Document</title>
</head>
<body>
<p>Test</p>
</body>
</html>
### Code block with Hugo's internal highlight shortcode
{{< highlight html "linenos=table,hl_lines=4 7-9" >}}
```html {title="example.html" lineNos=inline hl_lines=[4,"7-9"]}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@@ -107,7 +93,7 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
<p>Test</p> <p>Test</p>
</body> </body>
</html> </html>
{{< /highlight >}} ```
## List Types ## List Types
@@ -80,34 +80,20 @@ Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sap
</html> </html>
``` ```
### 4スペースのインデントによるコードブロック ### タイトルと行ハイライト機能付きのコードブロック
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>HTML5 資料の例</title>
</head>
<body>
<p>テスト</p>
</body>
</html>
### Hugo 内のショートコード・ハイライトを利用したコードブロック
{{< highlight html "linenos=table,hl_lines=4 7-9" >}}
```html {title="example.html" lineNos=inline hl_lines=[4,"7-9"]}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ja"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>HTML5 資料の例</title> <title>Example HTML5 Document</title>
</head> </head>
<body> <body>
<p>テスト</p> <p>Test</p>
</body> </body>
</html> </html>
{{< /highlight >}} ```
## リスト形式 ## リスト形式
+4 -18
View File
@@ -65,7 +65,7 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
## Code Blocks ## Code Blocks
### Code block with backticks ### General code block
```html ```html
<!DOCTYPE html> <!DOCTYPE html>
@@ -80,23 +80,9 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
</html> </html>
``` ```
### Code block indented with four spaces ### Code block with title and line highlight
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example HTML5 Document</title>
</head>
<body>
<p>Test</p>
</body>
</html>
### Code block with Hugo's internal highlight shortcode
{{< highlight html "linenos=table,hl_lines=4 7-9" >}}
```html {title="example.html" lineNos=inline hl_lines=[4,"7-9"]}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@@ -107,7 +93,7 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
<p>Test</p> <p>Test</p>
</body> </body>
</html> </html>
{{< /highlight >}} ```
## List Types ## List Types
@@ -65,7 +65,7 @@ Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sap
## 代码块 ## 代码块
### 带反引号的代码块 ### 一般的代码块
```html ```html
<!DOCTYPE html> <!DOCTYPE html>
@@ -80,23 +80,9 @@ Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sap
</html> </html>
``` ```
### 缩进四个空格的代码块 ### 带有标题和行高亮的代码块
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example HTML5 Document</title>
</head>
<body>
<p>Test</p>
</body>
</html>
### 带有 Hugo 内部高亮简码的代码块
{{< highlight html "linenos=table,hl_lines=4 7-9" >}}
```html {title="example.html" lineNos=inline hl_lines=[4,"7-9"]}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@@ -107,7 +93,7 @@ Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sap
<p>Test</p> <p>Test</p>
</body> </body>
</html> </html>
{{< /highlight >}} ```
## 列表 ## 列表
@@ -0,0 +1,10 @@
{{- $title := or .Attributes.title "" -}}
{{- $lang := or .Type "text" -}}
<div class="highlight-wrapper">
{{- with $title -}}
<div class="codeblock-title">
{{- $title -}}
</div>
{{- end -}}
{{- transform.Highlight .Inner $lang .Options -}}
</div>