From fa94e69877511c54e339ddd7b3c2d3da5272d56b Mon Sep 17 00:00:00 2001
From: Cell <1024@lruihao.cn>
Date: Tue, 14 Oct 2025 15:03:45 +0800
Subject: [PATCH] feat: add JSON Viewer support and related configurations
(#643)
* feat: add JSON Viewer support and related configurations
* feat: add JSON Viewer initialization and theme switching support
---
.github/dependabot.yml | 2 +-
apps/test/content/posts/json-viewer-test.md | 84 +++++++++++++++++++
assets/data/cdn/jsdelivr.yml | 2 +
assets/data/cdn/unpkg.yml | 2 +
assets/js/theme.js | 16 ++++
.../json-viewer-element.umd.js | 1 +
hugo.toml | 9 ++
i18n/de.toml | 4 +-
i18n/en.toml | 2 +
i18n/es.toml | 2 +
i18n/fr.toml | 2 +
i18n/hi.toml | 6 +-
i18n/it.toml | 6 +-
i18n/pl.toml | 2 +
i18n/pt-BR.toml | 4 +-
i18n/ro.toml | 2 +
i18n/ru.toml | 6 +-
i18n/sr.toml | 6 +-
i18n/vi.toml | 4 +-
i18n/zh-CN.toml | 2 +
i18n/zh-TW.toml | 6 +-
layouts/_markup/render-codeblock-json.html | 22 +++++
layouts/_partials/assets.html | 6 ++
23 files changed, 184 insertions(+), 14 deletions(-)
create mode 100644 apps/test/content/posts/json-viewer-test.md
create mode 100644 assets/lib/json-viewer-element/json-viewer-element.umd.js
create mode 100644 layouts/_markup/render-codeblock-json.html
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 58626632..44c04d8e 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,7 +1,7 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
-# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
diff --git a/apps/test/content/posts/json-viewer-test.md b/apps/test/content/posts/json-viewer-test.md
new file mode 100644
index 00000000..f4ca0e29
--- /dev/null
+++ b/apps/test/content/posts/json-viewer-test.md
@@ -0,0 +1,84 @@
+---
+title: JSON Viewer Test
+date: 2025-10-14T12:29:06+08:00
+collections:
+ - Tests
+categories:
+ - Markdown
+tags:
+ - json
+---
+
+Testing JSON viewer in FixIt theme.
+
+```json {boxed=false}
+{
+ "foo": "bar"
+}
+```
+
+
+
+## JSON Viewer
+
+```json
+{
+ "name": "John Doe",
+ "age": 30,
+ "isEmployed": true,
+ "address": {
+ "street": "123 Main St",
+ "city": "Anytown",
+ "state": "CA",
+ "postalCode": "12345"
+ },
+ "phoneNumbers": [
+ {
+ "type": "home",
+ "number": "555-1234"
+ },
+ {
+ "type": "work",
+ "number": "555-5678"
+ }
+ ],
+ "children": [],
+ "spouse": null
+}
+```
+
+disabled copy:
+
+```json {copyable=false}
+{
+ "foo": "bar"
+}
+```
+
+## JSON Code
+
+```json {enable=false}
+{
+ "name": "John Doe",
+ "age": 30,
+ "isEmployed": true,
+ "address": {
+ "street": "123 Main St",
+ "city": "Anytown",
+ "state": "CA",
+ "postalCode": "12345"
+ },
+ "phoneNumbers": [
+ {
+ "type": "home",
+ "number": "555-1234"
+ },
+ {
+ "type": "work",
+ "number": "555-5678"
+ }
+ ],
+ "children": [],
+ "spouse": null
+}
+```
diff --git a/assets/data/cdn/jsdelivr.yml b/assets/data/cdn/jsdelivr.yml
index 7074e1e7..cadff7ff 100644
--- a/assets/data/cdn/jsdelivr.yml
+++ b/assets/data/cdn/jsdelivr.yml
@@ -39,6 +39,8 @@ libFiles:
gitalkJS: gitalk@1.7.2/dist/gitalk.min.js
# instant.page@5.2.0 https://github.com/instantpage/instant.page
instantPage: instant.page@5.2.0/instantpage.min.js
+ # json-viewer-element@1.0.0 https://github.com/Lruihao/json-viewer-element
+ jsonViewerElementJS: json-viewer-element@1.0.0/dist/json-viewer-element.umd.js
# katex@0.16.22 https://github.com/KaTeX/KaTeX
katexCopyTexJS: katex@0.16.22/dist/contrib/copy-tex.min.js
katexCSS: katex@0.16.22/dist/katex.min.css
diff --git a/assets/data/cdn/unpkg.yml b/assets/data/cdn/unpkg.yml
index 2e6e25e4..2a60f2d0 100644
--- a/assets/data/cdn/unpkg.yml
+++ b/assets/data/cdn/unpkg.yml
@@ -39,6 +39,8 @@ libFiles:
gitalkJS: gitalk@1.7.2/dist/gitalk.min.js
# instant.page@5.2.0 https://github.com/instantpage/instant.page
instantPage: instant.page@5.2.0/instantpage.js
+ # json-viewer-element@1.0.0 https://github.com/Lruihao/json-viewer-element
+ jsonViewerElementJS: json-viewer-element@1.0.0/dist/json-viewer-element.umd.js
# katex@0.16.22 https://github.com/KaTeX/KaTeX
katexCopyTexJS: katex@0.16.22/dist/contrib/copy-tex.min.js
katexCSS: katex@0.16.22/dist/katex.min.css
diff --git a/assets/js/theme.js b/assets/js/theme.js
index 20c8cecc..8ca3e3b2 100644
--- a/assets/js/theme.js
+++ b/assets/js/theme.js
@@ -1083,6 +1083,19 @@ class FixIt {
window.MathJax?.typeset && window.MathJax.typeset();
}
+ initJsonViewer() {
+ if (!window.JsonViewerElement) {
+ return;
+ }
+ this._jsonViewerOnSwitchTheme = this._jsonViewerOnSwitchTheme || (() => {
+ this.util.forEach(document.getElementsByTagName('json-viewer'), ($el) => {
+ $el.setAttribute('theme', this.isDark ? 'dark' : 'light');
+ });
+ });
+ this.switchThemeEventSet.add(this._jsonViewerOnSwitchTheme);
+ this._jsonViewerOnSwitchTheme();
+ }
+
initFixItDecryptor() {
this.decryptor = new FixItDecryptor({
decrypted: () => {
@@ -1100,6 +1113,7 @@ class FixIt {
this.initTocListener();
this.initPangu();
this.initMathJax();
+ this.initJsonViewer();
window.FixItMermaid?.init?.();
this.util.forEach(document.querySelectorAll('.encrypted-hidden'), ($element) => {
$element.classList.replace('encrypted-hidden', 'decrypted-shown');
@@ -1117,6 +1131,7 @@ class FixIt {
this.initMapbox();
this.initPangu();
this.initMathJax();
+ this.initJsonViewer();
window.FixItMermaid?.init?.();
this.util.forEach($content.querySelectorAll('.encrypted-hidden'), ($element) => {
$element.classList.replace('encrypted-hidden', 'decrypted-shown');
@@ -1318,6 +1333,7 @@ class FixIt {
this.initTypeit();
this.initMapbox();
this.initPangu();
+ this.initJsonViewer();
}
this.initThemeColor();
this.initSVGIcon();
diff --git a/assets/lib/json-viewer-element/json-viewer-element.umd.js b/assets/lib/json-viewer-element/json-viewer-element.umd.js
new file mode 100644
index 00000000..d9751843
--- /dev/null
+++ b/assets/lib/json-viewer-element/json-viewer-element.umd.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).JsonViewerElement={})}(this,function(e){"use strict";const t=document.createElement("template");t.innerHTML='\n\n
\n\n \n\n';class n extends HTMLElement{constructor(){super(),this._value=null,this.root=this.attachShadow({mode:"open"}),this.root.appendChild(t.content.cloneNode(!0)),this.container=this.root.getElementById("root")}static get observedAttributes(){return["value","expand-depth","copyable","sort","boxed","theme","parse"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}set value(e){e!==this._value&&(this._value=e,this.render())}get value(){return this._value??this.getAttribute("value")}get expandDepth(){return Number(this.getAttribute("expand-depth")??1)}get sort(){return this.hasAttribute("sort")}get theme(){return this.getAttribute("theme")||"light"}get parse(){return"false"!==this.getAttribute("parse")}get copyable(){if(!this.hasAttribute("copyable"))return!1;const e=this.getAttribute("copyable"),t={copyText:"Copy",copiedText:"Copied",timeout:2e3,align:"right"};if(""===e||null===e)return t;try{return{...t,...JSON.parse(e)}}catch{return t}}copyText(e){return navigator.clipboard?(this.copyText=e=>navigator.clipboard.writeText(e),this.copyText(e)):(this.copyText=e=>new Promise((t,n)=>{const o=document.createElement("input");o.value=e,document.body.appendChild(o),o.select(),document.execCommand("copy")?(document.body.removeChild(o),t()):(document.body.removeChild(o),n(new Error("Copy failed")))}),this.copyText(e))}render(){if("string"==typeof this.value&&this.parse)try{this._value=JSON.parse(this.value)}catch{}this.container.innerHTML="",this.container.appendChild(this.build(this._value,0));const e=this.copyable;if(e){const t=e.align||"right",n=this.root.querySelector('slot[name="copy-button"]'),o=n.assignedElements()[0],r=this.root.querySelector(".jv-copy");if(n.hidden=!1,n.className=`align-${t}`,!o){let t;r.textContent=e.copyText;const n=r.cloneNode(!0);r.replaceWith(n),n.textContent=e.copyText,n.addEventListener("click",()=>{const o=JSON.stringify(this._value,null,2);this.copyText(o).then(()=>{n.textContent=e.copiedText,t=window.setTimeout(()=>{n.textContent=e.copyText,clearTimeout(t)},e.timeout),this.dispatchEvent(new CustomEvent("copy-success",{detail:{text:o,options:e}}))}).catch(()=>{console.warn("Failed to copy text to clipboard"),this.dispatchEvent(new CustomEvent("copy-error",{detail:{text:o,options:e}}))})})}}}build(e,t){if(null===e)return this.leaf("null","jv-null");if(void 0===e)return this.leaf("undefined","jv-undefined");if("boolean"==typeof e)return this.leaf(String(e),"jv-boolean");if("number"==typeof e)return this.leaf(String(e),"jv-number");if("string"==typeof e)return this.leaf(`"${e}"`,"jv-string");if("function"==typeof e)return this.leaf("","jv-function");if(e instanceof RegExp)return this.leaf("","jv-regexp");if(e instanceof Date)return this.leaf(`"${e.toLocaleString()}"`,"jv-string");const n=Array.isArray(e),o=document.createElement("span");o.className="jv-node",o.setAttribute("part","node");const r=document.createElement("div");r.className="jv-list",r.setAttribute("part","list");const i=n?this.sort?[...e.keys()].sort((e,t)=>e-t):[...e.keys()]:this.sort?Object.keys(e).sort():Object.keys(e);for(const l of i){const o=document.createElement("div"),i=this.build(e[l],t+1);if(o.className="jv-item",i instanceof Element&&i.classList.contains("jv-node")){const e=i.querySelector(".jv-toggle");e&&(e.remove(),o.append(e))}if(!n){const e=document.createElement("span");e.className="jv-key",e.setAttribute("part","key"),e.textContent=`"${l}": `,o.append(e)}o.append(i),r.append(o)}const s=document.createElement("span");s.className="jv-toggle",s.setAttribute("part","toggle"),o.classList.contains("collapsed")||s.classList.add("open"),s.addEventListener("click",()=>{o.classList.toggle("collapsed"),s.classList.toggle("open"),this.dispatchEvent(new CustomEvent("toggle",{detail:{node:o,data:e,isCollapsed:o.classList.contains("collapsed")}}))});const a=document.createElement("span");return a.className="jv-ellipsis",a.setAttribute("part","ellipsis"),a.textContent=`...${i.length}`,a.addEventListener("click",()=>{o.classList.remove("collapsed"),s.classList.add("open")}),t>=this.expandDepth&&(o.classList.add("collapsed"),s.classList.remove("open")),i.length||o.classList.add("empty"),o.append(s,n?"[":"{",a,r,n?"]":"}"),o}leaf(e,t){const n=document.createElement("span");return n.className=`jv-value ${t}`,n.setAttribute("part",`value ${t.replace("jv-","")}`),n.textContent=e,n}}customElements.define("json-viewer",n),e.JsonViewerElement=n,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
diff --git a/hugo.toml b/hugo.toml
index a3d73653..69c69340 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -1083,6 +1083,15 @@ cacheRemote = false
# Image resizing and optimisation
optimise = false
+# FixIt 0.4.0 | NEW JSON Viewer config
+# See https://github.com/Lruihao/json-viewer-element
+[params.jsonViewer]
+enable = true
+expandDepth = 1
+copyable = true
+sort = false
+boxed = true
+
# FixIt 0.3.12 | NEW Custom partials config
# Custom partials must be stored in the /layouts/partials/ directory.
# Depends on open custom blocks https://fixit.lruihao.cn/references/blocks/
diff --git a/i18n/de.toml b/i18n/de.toml
index d5c7ac6a..c59144ed 100644
--- a/i18n/de.toml
+++ b/i18n/de.toml
@@ -97,8 +97,10 @@ clear = "Leeren"
cancel = "Abbrechen"
noResultsFound = "Keine Ergebnisse gefunden"
copyToClipboard = "In Zwischenablage kopieren"
+copyText = "Kopieren"
+copiedText = "Kopiert"
editLockTitle = "Bearbeitbaren Codeblock sperren"
-editUnLockTitle = "Bearbeiten des Codeblocks entsperren"
+editUnLockTitle = "Bearbeitbaren Codeblock entsperren"
cookieconsentMessage = "Diese Website verwendet Cookies, um Ihre Erfahrung zu verbessern."
cookieconsentDismiss = "Zustimmen"
cookieconsentLink = "Erfahren Sie mehr"
diff --git a/i18n/en.toml b/i18n/en.toml
index 9550cfb3..2cd70742 100644
--- a/i18n/en.toml
+++ b/i18n/en.toml
@@ -97,6 +97,8 @@ clear = "Clear"
cancel = "Cancel"
noResultsFound = "No results found"
copyToClipboard = "Copy to clipboard"
+copyText = "Copy"
+copiedText = "Copied"
editLockTitle = "Lock editable code block"
editUnLockTitle = "Unlock editable code block"
cookieconsentMessage = "This website uses Cookies to improve your experience."
diff --git a/i18n/es.toml b/i18n/es.toml
index ecaef7d8..20b66132 100644
--- a/i18n/es.toml
+++ b/i18n/es.toml
@@ -97,6 +97,8 @@ clear = "Limpiar"
cancel = "Cancelar"
noResultsFound = "No se encontraron resultados"
copyToClipboard = "Copiar al portapapeles"
+copyText = "Copiar"
+copiedText = "Copiado"
editLockTitle = "Bloquear bloque de código editable"
editUnLockTitle = "Desbloquear bloque de código editable"
cookieconsentMessage = "Este sitio web utiliza Cookies para mejorar su experiencia."
diff --git a/i18n/fr.toml b/i18n/fr.toml
index e47deeb6..e686eaac 100644
--- a/i18n/fr.toml
+++ b/i18n/fr.toml
@@ -97,6 +97,8 @@ clear = "Effacer"
cancel = "Annuler"
noResultsFound = "Aucun résultat trouvé"
copyToClipboard = "Copier dans le presse-papiers"
+copyText = "Copier"
+copiedText = "Copié"
editLockTitle = "Verrouiller le bloc de code modifiable"
editUnLockTitle = "Déverrouiller le bloc de code modifiable"
cookieconsentMessage = "Ce site Web utilise des Cookies pour améliorer votre expérience."
diff --git a/i18n/hi.toml b/i18n/hi.toml
index 8ad240c1..2ea2a133 100644
--- a/i18n/hi.toml
+++ b/i18n/hi.toml
@@ -98,8 +98,10 @@ clear = "साफ़ करें"
cancel = "रद्द करें"
noResultsFound = "कोई परिणाम नहीं मिला"
copyToClipboard = "क्लिपबोर्ड पर कॉपी करें"
-editLockTitle = "संपादन योग्य कोड ब्लॉक को लॉक करें"
-editUnLockTitle = "संपादन योग्य कोड ब्लॉक को अनलॉक करें"
+copyText = "कॉपी करें"
+copiedText = "कॉपी किया गया"
+editLockTitle = "संपादन योग्य कोड ब्लॉक लॉक करें"
+editUnLockTitle = "संपादन योग्य कोड ब्लॉक अनलॉक करें"
cookieconsentMessage = "यह वेबसाइट आपके अनुभव को बेहतर बनाने के लिए कुकीज़ का उपयोग करती है।"
cookieconsentDismiss = "समझ गया!"
cookieconsentLink = "और अधिक जानें"
diff --git a/i18n/it.toml b/i18n/it.toml
index f12634ba..2f61067a 100644
--- a/i18n/it.toml
+++ b/i18n/it.toml
@@ -97,8 +97,10 @@ clear = "Chiaro"
cancel = "Annulla"
noResultsFound = "Nessun risultato trovato"
copyToClipboard = "Copia negli appunti"
-editLockTitle = "Blocca blocco di codice modificabile"
-editUnLockTitle = "Sblocca il blocco di codice modificabile"
+copyText = "Copia"
+copiedText = "Copiato"
+editLockTitle = "Blocca blocco codice modificabile"
+editUnLockTitle = "Sblocca blocco codice modificabile"
cookieconsentMessage = "Questo sito Web utilizza i Cookies per migliorare la tua esperienza."
cookieconsentDismiss = "Essere d'accordo"
cookieconsentLink = "Per saperne di più"
diff --git a/i18n/pl.toml b/i18n/pl.toml
index 1669d292..9323732d 100644
--- a/i18n/pl.toml
+++ b/i18n/pl.toml
@@ -97,6 +97,8 @@ clear = "Pusty"
cancel = "Anuluj"
noResultsFound = "Nie znaleziono wyników"
copyToClipboard = "Skopiuj do schowka"
+copyText = "Kopiuj"
+copiedText = "Skopiowano"
editLockTitle = "Zablokuj edytowalny blok kodu"
editUnLockTitle = "Odblokuj edytowalny blok kodu"
cookieconsentMessage = "Ta strona korzysta z plików Cookies, aby poprawić komfort użytkowania."
diff --git a/i18n/pt-BR.toml b/i18n/pt-BR.toml
index fc4d5c61..4ecf59bf 100644
--- a/i18n/pt-BR.toml
+++ b/i18n/pt-BR.toml
@@ -98,8 +98,10 @@ clear = "Limpar"
cancel = "Cancelar"
noResultsFound = "Nenhum resultado encontrado"
copyToClipboard = "Copiar para a área de transferência"
+copyText = "Copiar"
+copiedText = "Copiado"
editLockTitle = "Bloquear bloco de código editável"
-editUnLockTitle = "Desbloquear o bloco de código editável"
+editUnLockTitle = "Desbloquear bloco de código editável"
cookieconsentMessage = "Este site usa Cookies para melhorar sua experiência."
cookieconsentDismiss = "Aceitar"
cookieconsentLink = "Saber mais"
diff --git a/i18n/ro.toml b/i18n/ro.toml
index 32908af2..1a6d1c15 100644
--- a/i18n/ro.toml
+++ b/i18n/ro.toml
@@ -97,6 +97,8 @@ clear = "Golire"
cancel = "Anulare"
noResultsFound = "Nici un rezultat gasit"
copyToClipboard = "Copiați în clipboard"
+copyText = "Copiază"
+copiedText = "Copiat"
editLockTitle = "Blocați blocul de cod editabil"
editUnLockTitle = "Deblocați blocul de cod editabil"
cookieconsentMessage = "Acest site web utilizează Cookies pentru a vă îmbunătăți experiența."
diff --git a/i18n/ru.toml b/i18n/ru.toml
index 9e9abeac..fff61368 100644
--- a/i18n/ru.toml
+++ b/i18n/ru.toml
@@ -95,9 +95,11 @@ searchIn = "Поиск в {{ . }}"
gotoResultsPage = "Перейти на страницу результатов поиска ..."
clear = "Очистить"
cancel = "Отменить"
-noResultsFound = "Результатов не найдено"
+noResultsFound = "Результаты не найдены"
copyToClipboard = "Копировать в буфер обмена"
-editLockTitle = "Заблокировать редактируемый кодовый блок"
+copyText = "Копировать"
+copiedText = "Скопировано"
+editLockTitle = "Заблокировать редактируемый блок кода"
editUnLockTitle = "Разблокировать редактируемый блок кода"
cookieconsentMessage = "Этот сайт использует Cookies для улучшения вашего опыта."
cookieconsentDismiss = "Согласен"
diff --git a/i18n/sr.toml b/i18n/sr.toml
index 8e4d841e..dff9538b 100644
--- a/i18n/sr.toml
+++ b/i18n/sr.toml
@@ -95,10 +95,12 @@ searchIn = "Претражи у {{ . }}"
gotoResultsPage = "Иди на страницу резултата претраге ..."
clear = "Очисти"
cancel = "Поништи"
-noResultsFound = "Без резултата"
+noResultsFound = "Резултати нису пронађени"
copyToClipboard = "Копирај на радну таблу"
+copyText = "Копирај"
+copiedText = "Копирано"
editLockTitle = "Закључај блок кода који се може уређивати"
-editUnLockTitle = "Откључајте блок кода који се може уређивати"
+editUnLockTitle = "Откључај блок кода који се може уређивати"
cookieconsentMessage = "Ова веб локација користи Cookies да би побољшала ваше искуство."
cookieconsentDismiss = "Договорити се"
cookieconsentLink = "Сазнајте више"
diff --git a/i18n/vi.toml b/i18n/vi.toml
index 31600e04..a6b8a13e 100644
--- a/i18n/vi.toml
+++ b/i18n/vi.toml
@@ -94,8 +94,10 @@ searchIn = "Tìm kiếm trong {{ . }}"
gotoResultsPage = "Đi đến trang kết quả tìm kiếm ..."
clear = "Xoá"
cancel = "Huỷ"
-noResultsFound = "Không tìm thấy"
+noResultsFound = "Không tìm thấy kết quả"
copyToClipboard = "Sao chép vào bộ nhớ tạm"
+copyText = "Sao chép"
+copiedText = "Đã sao chép"
editLockTitle = "Khóa khối mã có thể chỉnh sửa"
editUnLockTitle = "Mở khóa khối mã có thể chỉnh sửa"
cookieconsentMessage = "Trang web này sử dụng Cookies để cải thiện trải nghiệm của bạn."
diff --git a/i18n/zh-CN.toml b/i18n/zh-CN.toml
index c4f027d2..f7b967cf 100644
--- a/i18n/zh-CN.toml
+++ b/i18n/zh-CN.toml
@@ -95,6 +95,8 @@ clear = "清空"
cancel = "取消"
noResultsFound = "没有找到结果"
copyToClipboard = "复制到剪贴板"
+copyText = "复制"
+copiedText = "已复制"
editLockTitle = "锁定可编辑代码块"
editUnLockTitle = "解锁可编辑代码块"
cookieconsentMessage = "本网站使用 Cookies 来改善您的浏览体验。"
diff --git a/i18n/zh-TW.toml b/i18n/zh-TW.toml
index c403c95a..7aa4dcdc 100644
--- a/i18n/zh-TW.toml
+++ b/i18n/zh-TW.toml
@@ -95,8 +95,10 @@ clear = "清除"
cancel = "取消"
noResultsFound = "沒有找到結果"
copyToClipboard = "複製到剪貼板"
-editLockTitle = "鎖定可編輯代碼塊"
-editUnLockTitle = "解鎖可編輯代碼塊"
+copyText = "複製"
+copiedText = "已複製"
+editLockTitle = "鎖定可編輯程式碼區塊"
+editUnLockTitle = "解鎖可編輯程式碼區塊"
cookieconsentMessage = "本網站使用 Cookies 來改善您的流覽體驗。"
cookieconsentDismiss = "同意"
cookieconsentLink = "瞭解更多"
diff --git a/layouts/_markup/render-codeblock-json.html b/layouts/_markup/render-codeblock-json.html
new file mode 100644
index 00000000..a8a0c22f
--- /dev/null
+++ b/layouts/_markup/render-codeblock-json.html
@@ -0,0 +1,22 @@
+{{- $jsonViewer := .Attributes | merge (.Page.Param "jsonViewer") -}}
+{{- if $jsonViewer.enable -}}
+ {{- $attrs := printf `expand-depth="%v"` $jsonViewer.expanddepth -}}
+ {{- $copyable := false -}}
+ {{- with $jsonViewer.copyable -}}
+ {{- $copyable = dict "copyText" (T "assets.copyText") "copiedText" (T "assets.copiedText") -}}
+ {{- end -}}
+ {{- with $jsonViewer.sort -}}
+ {{- $attrs = " sort" | add $attrs -}}
+ {{- end -}}
+ {{- with $jsonViewer.boxed -}}
+ {{- $attrs = " boxed" | add $attrs -}}
+ {{- end -}}
+
+ {{- .Page.Store.Set "hasJsonViewer" true -}}
+ {{- if eq hugo.Context.MarkupScope "home" -}}
+ {{- site.Home.Store.Set "hasJsonViewer" true -}}
+ {{- end -}}
+{{- else -}}
+ {{- $result := transform.HighlightCodeBlock . -}}
+ {{- $result.Wrapped -}}
+{{- end -}}
diff --git a/layouts/_partials/assets.html b/layouts/_partials/assets.html
index cdc1d517..17547786 100644
--- a/layouts/_partials/assets.html
+++ b/layouts/_partials/assets.html
@@ -60,6 +60,12 @@ FixIt theme assets partial
{{- dict "Source" $source "Fingerprint" $fingerprint "Attr" `type="module"` "Async" true "Defer" true | dict "Page" . "Data" | partial "store/script.html" -}}
{{- end -}}
+{{- /* JSON Viewer */ -}}
+{{- if .Store.Get "hasJsonViewer" -}}
+ {{- $source := $cdn.jsonViewerElementJS | default "lib/json-viewer-element/json-viewer-element.umd.js" -}}
+ {{- dict "Source" $source "Fingerprint" $fingerprint "Defer" true | dict "Page" . "Data" | partial "store/script.html" -}}
+{{- end -}}
+
{{- /* twemoji */ -}}
{{- if $params.twemoji -}}
{{- $source := $cdn.twemojiJS | default "lib/twemoji/twemoji.min.js" -}}