From 11e534bf2872bd08d1398a63c5251ebfc6981231 Mon Sep 17 00:00:00 2001 From: Mimi <1119186082@qq.com> Date: Sat, 29 Jul 2023 07:41:50 +0800 Subject: [PATCH] Support folding code blocks (#679) --- _config.yml | 4 ++ scripts/helpers/next-config.js | 1 + .../_common/scaffolding/highlight/fold.styl | 29 ++++++++++++ .../_common/scaffolding/highlight/index.styl | 1 + source/js/next-boot.js | 2 +- source/js/utils.js | 44 +++++++++++++------ 6 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 source/css/_common/scaffolding/highlight/fold.styl diff --git a/_config.yml b/_config.yml index 7cb1b6929..e7bb2921a 100644 --- a/_config.yml +++ b/_config.yml @@ -373,6 +373,10 @@ codeblock: enable: false # Available values: default | flat | mac style: + # Fold code block + fold: + enable: false + height: 500 back2top: enable: true diff --git a/scripts/helpers/next-config.js b/scripts/helpers/next-config.js index 25c28a3e3..824644f72 100644 --- a/scripts/helpers/next-config.js +++ b/scripts/helpers/next-config.js @@ -19,6 +19,7 @@ hexo.extend.helper.register('next_config', function() { exturl : theme.exturl, sidebar : theme.sidebar, copycode : theme.codeblock.copy_button, + fold : theme.codeblock.fold, bookmark : theme.bookmark, mediumzoom: theme.mediumzoom, lazyload : theme.lazyload, diff --git a/source/css/_common/scaffolding/highlight/fold.styl b/source/css/_common/scaffolding/highlight/fold.styl new file mode 100644 index 000000000..5168e7637 --- /dev/null +++ b/source/css/_common/scaffolding/highlight/fold.styl @@ -0,0 +1,29 @@ +.expand-btn { + bottom: 0; + color: var(--highlight-foreground); + cursor: pointer; + display: none; + left: 0; + right: 0; + position: absolute; + text-align: center; +} + +.fold-cover { + background-image: linear-gradient(to top, var(--highlight-background) 0, rgba(0, 0, 0, 0) 100%); + bottom: 0; + display: none; + height: 50px; + left: 0; + right: 0; + position: absolute; +} + +.highlight-fold { + max-height: unit(hexo-config('codeblock.fold.height'), 'px'); + overflow-y: hidden !important; + + .expand-btn, .fold-cover { + display: block; + } +} diff --git a/source/css/_common/scaffolding/highlight/index.styl b/source/css/_common/scaffolding/highlight/index.styl index 43d897f7f..3115966b8 100644 --- a/source/css/_common/scaffolding/highlight/index.styl +++ b/source/css/_common/scaffolding/highlight/index.styl @@ -13,6 +13,7 @@ if (hexo-config('darkmode')) { } @require 'copy-code' if (hexo-config('codeblock.copy_button.enable')); +@require 'fold' if (hexo-config('codeblock.fold.enable')); // Placeholder: $code-inline $code-block $code-inline { diff --git a/source/js/next-boot.js b/source/js/next-boot.js index 1225fd2da..2ed68a885 100644 --- a/source/js/next-boot.js +++ b/source/js/next-boot.js @@ -46,7 +46,7 @@ NexT.boot.refresh = function() { CONFIG.exturl && NexT.utils.registerExtURL(); NexT.utils.wrapTableWithBox(); - NexT.utils.registerCopyCode(); + NexT.utils.registerCodeblock(); NexT.utils.registerTabsTag(); NexT.utils.registerActiveMenuItem(); NexT.utils.registerLangSelect(); diff --git a/source/js/utils.js b/source/js/utils.js index a2cc0d740..a0416b33a 100644 --- a/source/js/utils.js +++ b/source/js/utils.js @@ -39,30 +39,48 @@ NexT.utils = { }); }, - /** - * One-click copy code support. - */ - registerCopyCode: function() { + registerCodeblock: function() { let figure = document.querySelectorAll('figure.highlight'); - let needWrap = false; + let isHljsWithWrap = true; if (figure.length === 0) { figure = document.querySelectorAll('pre:not(.mermaid)'); - needWrap = true; + isHljsWithWrap = false; } figure.forEach(element => { - element.querySelectorAll('.code .line span').forEach(span => { - span.classList.forEach(name => { - span.classList.replace(name, `hljs-${name}`); + let span = element.querySelectorAll('.code .line span'); + if (span.length === 0) { + // Hljs without line_number and wrap + span = element.querySelectorAll('code.highlight span'); + } + span.forEach(s => { + s.classList.forEach(name => { + s.classList.replace(name, `hljs-${name}`); }); }); - if (!CONFIG.copycode.enable) return; - let target = element; - if (needWrap) { + const height = parseInt(window.getComputedStyle(element).height.replace('px', ''), 10); + const needFold = CONFIG.fold.enable && (height > CONFIG.fold.height); + if (!needFold && !CONFIG.copycode.enable) return; + let target; + if (isHljsWithWrap && CONFIG.copycode.style === 'mac') { + target = element; + } else { + // https://github.com/next-theme/hexo-theme-next/issues/98 + // https://github.com/next-theme/hexo-theme-next/pull/508 + const container = element.querySelector('.table-container') || element; const box = document.createElement('div'); box.className = 'code-container'; - element.wrap(box); + container.wrap(box); target = box; } + if (needFold) { + target.classList.add('highlight-fold'); + target.insertAdjacentHTML('beforeend', '
'); + target.querySelector('.expand-btn').addEventListener('click', () => { + target.classList.remove('highlight-fold'); + }); + } + if (!CONFIG.copycode.enable) return; + // One-click copy code support. target.insertAdjacentHTML('beforeend', '
'); const button = target.querySelector('.copy-btn'); button.addEventListener('click', () => {