feat(code): add download button for code blocks and related functionality (#706)

This commit is contained in:
Cell
2026-03-02 17:34:57 +08:00
committed by GitHub
parent 83a658ba25
commit 6196cd5edf
20 changed files with 58 additions and 1 deletions
+6
View File
@@ -237,6 +237,12 @@ pre {
color: fixit-var(global-link-hover-color);
}
.download-btn[data-downloaded] .fa-download {
--fa: "\f1ce";
font-weight: 900;
color: fixit-var(global-link-hover-color);
}
@each $type, $text in $code-type-map {
&.language-#{to-lower-case($type)} {
// e.g., --fi-code-type: "JavaScript";
+28
View File
@@ -459,6 +459,33 @@ class FixIt {
}, false);
}
initDownloadCode(codeBlock, codePreEl) {
const downloadBtn = codeBlock.querySelector('.code-header .download-btn');
if (!downloadBtn) return;
downloadBtn.addEventListener('click', () => {
const $codeHeader = codeBlock.querySelector('.code-header');
const fileNameFromTitle = $codeHeader?.querySelector('.code-title')?.dataset.name?.trim();
const language = Array.from($codeHeader?.classList || []).find((className) => className.startsWith('language-'))?.replace('language-', '');
const fallbackName = language && language !== 'fallback' ? `code.${language}` : 'code.txt';
const fileName = (fileNameFromTitle || fallbackName).replace(/[\\/:*?"<>|\r\n]+/g, '-');
const blob = new Blob([codePreEl.innerText], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = fileName || fallbackName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
downloadBtn.toggleAttribute('data-downloaded', true);
downloadBtn.classList.toggle('fa-spin', true);
setTimeout(() => {
downloadBtn.toggleAttribute('data-downloaded', false);
downloadBtn.classList.toggle('fa-spin', false);
}, 300);
}, false);
}
/**
* init code wrapper
*/
@@ -477,6 +504,7 @@ class FixIt {
if ($codeBlock.dataset.mode === 'classic') {
const $codeHeader = $codeBlock.querySelector('.code-header');
if (!$codeHeader) return;
this.initDownloadCode($codeBlock, $codePreEl);
// code title
$codeHeader.querySelector('.code-title').addEventListener('click', () => {
$codeBlock.classList.toggle('is-collapsed');
+2
View File
@@ -1144,6 +1144,8 @@ wrapperClass = ""
maxShownLines = 10
# whether to enable code copy button
copyable = true
# [classic] whether to enable code download button in the code block header
downloadable = false
# [classic] whether to enable line numbers toggle button in the code block header
lineNosToggler = true
# [classic] whether to enable toggle line wrapping button in the code block header
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Kopiert"
toggleLineNumbers = "Zeilennummern umschalten"
toggleLineWrap = "Zeilenumbruch umschalten"
toggleCodeEditable = "Codeblock editierbar umschalten"
downloadCode = "Code herunterladen"
expandCode = "Codeblock erweitern oder reduzieren"
cookieconsentMessage = "Diese Website verwendet Cookies, um Ihre Erfahrung zu verbessern."
cookieconsentDismiss = "Zustimmen"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Copied"
toggleLineNumbers = "Toggle line numbers"
toggleLineWrap = "Toggle code wrap"
toggleCodeEditable = "Toggle code block editable"
downloadCode = "Download code"
expandCode = "Expand or collapse code block"
cookieconsentMessage = "This website uses Cookies to improve your experience."
cookieconsentDismiss = "Got it!"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Copiado"
toggleLineNumbers = "Alternar números de línea"
toggleLineWrap = "Alternar ajuste de línea"
toggleCodeEditable = "Alternar bloque de código editable"
downloadCode = "Descargar código"
expandCode = "Expandir o contraer bloque de código"
cookieconsentMessage = "Este sitio web utiliza Cookies para mejorar su experiencia."
cookieconsentDismiss = "De acuerdo"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Copié"
toggleLineNumbers = "Basculer les numéros de ligne"
toggleLineWrap = "Basculer le retour à la ligne"
toggleCodeEditable = "Basculer le bloc de code modifiable"
downloadCode = "Télécharger le code"
expandCode = "Développer ou réduire le bloc de code"
cookieconsentMessage = "Ce site Web utilise des Cookies pour améliorer votre expérience."
cookieconsentDismiss = "J'ai compris !"
+1
View File
@@ -103,6 +103,7 @@ copiedText = "कॉपी किया गया"
toggleLineNumbers = "लाइन नंबर टॉगल करें"
toggleLineWrap = "लाइन रैप टॉगल करें"
toggleCodeEditable = "कोड ब्लॉक संपादन योग्य टॉगल करें"
downloadCode = "कोड डाउनलोड करें"
expandCode = "कोड ब्लॉक का विस्तार या संकुचित करें"
cookieconsentMessage = "यह वेबसाइट आपके अनुभव को बेहतर बनाने के लिए कुकीज़ का उपयोग करती है।"
cookieconsentDismiss = "समझ गया!"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Copiato"
toggleLineNumbers = "Attiva/disattiva i numeri di linea"
toggleLineWrap = "Attiva/disattiva il ritorno a capo del codice"
toggleCodeEditable = "Attiva/disattiva la modifica del blocco di codice"
downloadCode = "Scarica codice"
expandCode = "Espandi o riduci il blocco di codice"
cookieconsentMessage = "Questo sito Web utilizza i Cookies per migliorare la tua esperienza."
cookieconsentDismiss = "Essere d'accordo"
+1
View File
@@ -100,6 +100,7 @@ copiedText = "コピー済み"
toggleLineNumbers = "行番号の切り替え"
toggleLineWrap = "自動折り返しの切り替え"
toggleCodeEditable = "コードブロックの編集切り替え"
downloadCode = "コードをダウンロード"
expandCode = "コードブロックの展開/折りたたみ"
cookieconsentMessage = "このウェブサイトはクッキーを使用して体験を向上させます。"
cookieconsentDismiss = "同意する"
+1
View File
@@ -100,6 +100,7 @@ copiedText = "복사됨"
toggleLineNumbers = "줄 번호 전환"
toggleLineWrap = "자동 줄 바꿈 전환"
toggleCodeEditable = "코드 블록 편집 전환"
downloadCode = "코드 다운로드"
expandCode = "코드 블록 확장/축소"
cookieconsentMessage = "이 웹사이트는 쿠키를 사용하여 경험을 향상시킵니다."
cookieconsentDismiss = "동의"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Skopiowano"
toggleLineNumbers = "Przełącz numery linii"
toggleLineWrap = "Przełącz zawijanie linii"
toggleCodeEditable = "Przełącz edytowalny blok kodu"
downloadCode = "Pobierz kod"
expandCode = "Rozwiń lub zwiń blok kodu"
cookieconsentMessage = "Ta strona korzysta z plików Cookies, aby poprawić komfort użytkowania."
cookieconsentDismiss = "Zgodzić się"
+1
View File
@@ -103,6 +103,7 @@ copiedText = "Copiado"
toggleLineNumbers = "Alternar números de linha"
toggleLineWrap = "Alternar quebra de linha"
toggleCodeEditable = "Alternar bloco de código editável"
downloadCode = "Baixar código"
expandCode = "Expandir ou recolher bloco de código"
cookieconsentMessage = "Este site usa Cookies para melhorar sua experiência."
cookieconsentDismiss = "Aceitar"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Copiat"
toggleLineNumbers = "Comută numerele de linie"
toggleLineWrap = "Comută înfășurarea liniei"
toggleCodeEditable = "Comută blocul de cod editabil"
downloadCode = "Descarcă codul"
expandCode = "Extinde sau restrânge blocul de cod"
cookieconsentMessage = "Acest site web utilizează Cookies pentru a vă îmbunătăți experiența."
cookieconsentDismiss = "De acord"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Скопировано"
toggleLineNumbers = "Переключить номера строк"
toggleLineWrap = "Переключить перенос строк"
toggleCodeEditable = "Переключить редактируемый блок кода"
downloadCode = "Скачать код"
expandCode = "Развернуть или свернуть блок кода"
cookieconsentMessage = "Этот сайт использует Cookies для улучшения вашего опыта."
cookieconsentDismiss = "Согласен"
+1
View File
@@ -102,6 +102,7 @@ copiedText = "Копирано"
toggleLineNumbers = "Прекидач за бројеве линија"
toggleLineWrap = "Прекидач за оматање линија"
toggleCodeEditable = "Пребаци уређивање блока кода"
downloadCode = "Преузми код"
expandCode = "Прошири или смањи блок кода"
cookieconsentMessage = "Ова веб локација користи Cookies да би побољшала ваше искуство."
cookieconsentDismiss = "Договорити се"
+1
View File
@@ -101,6 +101,7 @@ copiedText = "Đã sao chép"
toggleLineNumbers = "Chuyển đổi số dòng"
toggleLineWrap = "Chuyển đổi xuống dòng"
toggleCodeEditable = "Chuyển đổi khối mã có thể chỉnh sửa"
downloadCode = "Tải mã"
expandCode = "Mở rộng hoặc thu gọn khối mã"
cookieconsentMessage = "Trang web này sử dụng Cookies để cải thiện trải nghiệm của bạn."
cookieconsentDismiss = "Đã hiểu!"
+1
View File
@@ -100,6 +100,7 @@ copiedText = "已复制"
toggleLineNumbers = "切换行号"
toggleLineWrap = "切换自动换行"
toggleCodeEditable = "切换可编辑代码块"
downloadCode = "下载代码"
expandCode = "展开或折叠代码块"
cookieconsentMessage = "本网站使用 Cookies 来改善您的浏览体验。"
cookieconsentDismiss = "同意"
+1
View File
@@ -100,6 +100,7 @@ copiedText = "已複製"
toggleLineNumbers = "切換行號"
toggleLineWrap = "切換自動換行"
toggleCodeEditable = "切換可編輯程式碼區塊"
downloadCode = "下載程式碼"
expandCode = "展開或摺疊程式碼區塊"
cookieconsentMessage = "本網站使用 Cookies 來改善您的流覽體驗。"
cookieconsentDismiss = "同意"
+6 -1
View File
@@ -7,6 +7,7 @@
{{- $lineWrapBtn := "" -}}
{{- $editBtn := "" -}}
{{- $copyBtn := "" -}}
{{- $downloadBtn := "" -}}
{{- $foldIcon := dict "Class" "arrow fa-solid fa-chevron-down" | partial "plugin/icon.html" -}}
{{- $titleEl := printf `<span class="code-title">%s</span>` $foldIcon -}}
{{- $ellipsisBtn := printf `<span class="ellipses-btn" aria-label="Show more options" role="button">%s</span>` (dict "Class" "fa-solid fa-ellipsis-h" | partial "plugin/icon.html") -}}
@@ -30,10 +31,14 @@
{{- $copyIcon := dict "Class" "fa-regular fa-clone" | partial "plugin/icon.html" -}}
{{- $copyBtn = printf `<span class="copy-btn" aria-label="%s" role="button" title="%s">%s</span>` (T "assets.copyToClipboard") (T "assets.copyToClipboard") $copyIcon -}}
{{- end -}}
{{- if $config.downloadable -}}
{{- $downloadIcon := dict "Class" "fa-solid fa-download" | partial "plugin/icon.html" -}}
{{- $downloadBtn = printf `<span class="download-btn" aria-label="%s" role="button" title="%s">%s</span>` (T "assets.downloadCode") (T "assets.downloadCode") $downloadIcon -}}
{{- end -}}
{{- with $config.name -}}
{{- $titleEl = replace $titleEl `<span class="code-title">` (printf `<span class="code-title" data-name="%s">` .) -}}
{{- end -}}
{{- $codeHeader := printf `<div class="code-header language-%s">%s%s%s%s%s%s</div>` $lang $titleEl $ellipsisBtn $lineNosBtn $lineWrapBtn $editBtn $copyBtn -}}
{{- $codeHeader := printf `<div class="code-header language-%s">%s%s%s%s%s%s%s</div>` $lang $titleEl $ellipsisBtn $lineNosBtn $lineWrapBtn $editBtn $copyBtn $downloadBtn -}}
{{- $wrapper = replaceRE `(<div class="code-wrapper">)` (printf "%s$1" $codeHeader) $wrapper -}}
{{- return $wrapper -}}