From be3cb043699ccfb10b10f696b925033d37e3877f Mon Sep 17 00:00:00 2001 From: PCloud Date: Sun, 28 Apr 2024 08:20:22 +0100 Subject: [PATCH] refactor: codeblock (#1225) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: codeblock * feat: implement wrap and toggle open animation * chore: handle max-height calculation correctly * chore: remove unnecessary js * chore: remove clipboardjs * feat: use icons * feat: add text wrap icon * feat: add style to icons * refactor: switch to typescript * chore: add global declaration * chore: optimise image resize method * fix: sharer wechat and mastodon icon Close #1247 * Disable autoplay (#1249) * Improve the `bilibili` shortcode with more options (#1250) * add variables * finished the initial dev of bilibili improvement next is documentation * rearrange bilibili options * added documentation for improved bilibili shortcode * fluent chinese * chore: disableHTTPCache for dev env * refactor: color scheme #1245 (#1253) * refactor: color scheme * refactor: colors in Tailwind Config * fix: scss variables use error * feat: partially adopt Prime Design for the dark theme * feat: pick selection color * feat: pick link color * feat: pick codeblock, table, blockquote color * feat: pick more colors * refactor: remove black theme * fix: code background color * refactor: extract primitive colors * refactor: use primitive colors in tailwind config * chore: use --verbose * chore: sync github CI build step --------- Co-authored-by: PCloud * chore: re-enable counter * fix: syntax highlightning * chore: format code * fix(style): do not wrap line number * feat: make line numbers fix position * chore: bad idea, revert * refactor: move all js logic into theme.ts * feat: support copy icon states * feat: implement line number toggle * feat: move all JavaScript to theme.ts * feat: support custom title * feat: init all states * feat: support maxShownLines * fix: correct color scheme * chore: switch icon back to svg * feat: expand code blocks before print * deprecate copy option * feat: add titles to buttons * feat: add docs * feat: support wrap option --------- Co-authored-by: CXwudi Co-authored-by: 恐咖兵糖 <0@ftls.xyz> --- README.md | 1 - README.zh-cn.md | 1 - assets/css/_partial/_single/_code.scss | 178 ++---------------- assets/css/main.css | 122 ++++++++++++ assets/data/cdn/jsdelivr.yml | 2 - assets/js/shims/clipboard.js | 1 - assets/js/{theme.js => theme.ts} | 137 +++++++------- assets/lib/clipboard/clipboard.min.js | 7 - exampleSite/config/_default/params.toml | 7 +- exampleSite/content/about/index.en.md | 1 - exampleSite/content/about/index.zh-cn.md | 1 - .../posts/basic-markdown-syntax/index.en.md | 115 ++++++++++- .../basic-markdown-syntax/index.zh-cn.md | 114 ++++++++++- .../posts/tests/codeblock-tests/index.en.md | 84 +++++++++ .../theme-documentation-basics/index.en.md | 2 - .../theme-documentation-basics/index.zh-cn.md | 2 - .../_default/_markup/render-codeblock.html | 112 +++++++++++ layouts/partials/assets.html | 13 +- package-lock.json | 34 ---- package.json | 1 - tailwind.config.js | 4 + 21 files changed, 621 insertions(+), 318 deletions(-) delete mode 100644 assets/js/shims/clipboard.js rename assets/js/{theme.js => theme.ts} (84%) delete mode 100644 assets/lib/clipboard/clipboard.min.js create mode 100644 exampleSite/content/posts/tests/codeblock-tests/index.en.md create mode 100644 layouts/_default/_markup/render-codeblock.html diff --git a/README.md b/README.md index 624c1443f..73b0ad6ae 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,6 @@ Thanks to the authors of following resources included in the theme: * [object-fit-images](https://github.com/fregante/object-fit-images) * [Twemoji](https://github.com/twitter/twemoji) * [lightgallery.js](https://github.com/sachinchoolur/lightgallery.js) -* [clipboard.js](https://github.com/zenorocha/clipboard.js) * [Sharer.js](https://github.com/ellisonleao/sharer.js) * [TypeIt](https://typeitjs.com/) * [KaTeX](https://katex.org/) diff --git a/README.zh-cn.md b/README.zh-cn.md index 79114c2cd..912b9979f 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -202,7 +202,6 @@ DoIt 主题中用到了以下项目,感谢它们的作者: * [object-fit-images](https://github.com/fregante/object-fit-images) * [Twemoji](https://github.com/twitter/twemoji) * [lightgallery.js](https://github.com/sachinchoolur/lightgallery.js) -* [clipboard.js](https://github.com/zenorocha/clipboard.js) * [Sharer.js](https://github.com/ellisonleao/sharer.js) * [TypeIt](https://typeitjs.com/) * [KaTeX](https://katex.org/) diff --git a/assets/css/_partial/_single/_code.scss b/assets/css/_partial/_single/_code.scss index d3d7d7249..e9ba759c9 100644 --- a/assets/css/_partial/_single/_code.scss +++ b/assets/css/_partial/_single/_code.scss @@ -1,7 +1,6 @@ code { display: inline-block; max-width: 100%; - padding: 0 .4rem; @include overflow-wrap(break-word); @include line-break(anywhere); font-size: $code-font-size; @@ -10,15 +9,6 @@ code { } pre { - padding: 0; - margin: .25rem .5rem .25rem .5rem; - @include tab-size(4); - - code { - padding: 0; - overflow: auto hidden; - } - img { min-height: 1em; max-height: 1.2em; @@ -52,153 +42,6 @@ pre, } } -.highlight { - line-height: 1.4em; - margin: .5rem 0; - - >.chroma { - position: relative; - - .code-header { - display: flex; - justify-content: space-between; - align-items: center; - box-sizing: border-box; - width: 100%; - font-family: $global-font-family; - font-weight: bold; - color: $code-info-color; - background: $code-background-color-code-header; - - &:hover { - cursor: pointer; - } - - .code-title { - width: 100%; - padding: .4rem; - } - - .code-title::after { - padding-left: .2rem; - content: 'Code'; - } - - @each $type, $text in $code-type-map { - &.#{$type} .code-title::after { - content: $text; - } - } - } - - .lntd:first-child { - min-width: 1.6rem; - text-align: right; - } - - .lntd:last-child { - width: 100%; - - pre { - @include max-content(min-width); - } - } - - .ln { - padding-right: .75rem; - } - - .hl { - display: block; - background-color: $code-background-color-code-hl; - } - - .ln, - .lnt { - color: $global-font-secondary-color; - } - - .arrow { - padding: 0 .2rem; - @include transition(transform 0.2s ease); - } - - .ellipses { - padding: .4rem; - } - - .copy { - display: none; - padding: .4rem; - - &:hover { - cursor: pointer; - color: $global-link-hover-color; - } - } - - .table-wrapper { - max-height: 0; - overflow: auto hidden; - transition: max-height 0.5s ease-out; - } - - &.open { - .code-header { - background: $code-header-color; - } - - .table-wrapper { - max-height: none; - } - - .arrow { - @include transform(rotate(90deg)); - } - - .ellipses { - display: none; - } - - .copy { - display: inline; - } - } - } - - /* Comment */ - .c, - /* CommentHashbang */ - .ch, - /* CommentMultiline */ - .cm, - /* CommentSingle */ - .c1, - /* CommentSpecial */ - .cs, - /* CommentPreproc */ - .cp, - /* CommentPreprocFile */ - .cpf { - font-style: italic - } - - /* GenericUnderline */ - .gl { - text-decoration: underline - } - - // @each $class, $color in $code-highlight-color-map { - // .#{$class} { color: $color; } - // } - - // [theme=dark] & { - // @each $class, $color in $code-highlight-color-map-dark { - // .#{$class} { color: $color; } - // } - // } -} - .gist { .gist-file, @@ -215,4 +58,23 @@ pre, } -} \ No newline at end of file +} + +.show-line-numbers > pre > code > span::before { + // line number for code block + counter-increment: codeblock; + content: counter(codeblock); + min-width: 5ch; + text-align: center; + background: var(--code-background-color); + color: var(--global-font-color); + text-wrap: nowrap; +} + +pre > code > span > span.cl { + margin-left: 1rem; +} + +.show-line-numbers > pre > code > span > span.cl { + margin-left: 0; +} diff --git a/assets/css/main.css b/assets/css/main.css index 0e4462313..1ab90c422 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -762,6 +762,25 @@ html.dark { --tw-contain-style: ; } +.tw-m-0 { + margin: 0px; +} + +.\!tw-my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.tw-mx-2 { + margin-left: 0.5rem; + margin-right: 0.5rem; +} + +.tw-my-2 { + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} + .tw-my-4 { margin-top: 1rem; margin-bottom: 1rem; @@ -775,14 +794,34 @@ html.dark { margin-right: 0.25rem; } +.\!tw-block { + display: block !important; +} + +.tw-block { + display: block; +} + .tw-inline-block { display: inline-block; } +.tw-flex { + display: flex; +} + +.tw-hidden { + display: none; +} + .tw-h-10 { height: 2.5rem; } +.\!tw-max-h-0 { + max-height: 0px !important; +} + .tw-max-h-4 { max-height: 1rem; } @@ -810,6 +849,32 @@ html.dark { animation: tw-spin 1s linear infinite; } +.tw-select-none { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tw-flex-row { + flex-direction: row; +} + +.tw-justify-between { + justify-content: space-between; +} + +.tw-overflow-x-auto { + overflow-x: auto; +} + +.tw-overflow-y-hidden { + overflow-y: hidden; +} + +.tw-text-wrap { + text-wrap: wrap; +} + .tw-rounded-full { border-radius: 9999px; } @@ -823,10 +888,18 @@ html.dark { border-color: rgb(240 240 240 / var(--tw-border-opacity)); } +.tw-bg-bgColor-secondary { + background-color: var(--bgColor-secondary); +} + .tw-bg-transparent { background-color: transparent; } +.tw-p-0 { + padding: 0px; +} + .tw-p-4 { padding: 1rem; } @@ -854,10 +927,26 @@ html.dark { transition-duration: 150ms; } +.tw-transition-\[max-height\] { + transition-property: max-height; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.tw-transition-\[transform\] { + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + .tw-duration-300 { transition-duration: 300ms; } +.tw-duration-500 { + transition-duration: 500ms; +} + .tw-ease-in-out { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } @@ -866,12 +955,45 @@ html.dark { background-color: var(--bgColor-secondary); } +.hover\:tw-text-fgColor-link:hover { + color: var(--fgColor-link); +} + .hover\:tw-shadow-md:hover { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.tw-group.is-open .group-\[\.is-open\]\:tw-block { + display: block; +} + +.tw-group.is-open .group-\[\.is-open\]\:tw-hidden { + display: none; +} + +.tw-group.is-closed .group-\[\.is-closed\]\:\!tw-max-h-0 { + max-height: 0px !important; +} + +.tw-group.is-open .group-\[\.is-open\]\:tw-rotate-90 { + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.tw-group.is-wrap .group-\[\.is-wrap\]\:tw-text-wrap { + text-wrap: wrap; +} + +.tw-group.is-wrap .group-\[\.is-wrap\]\:tw-text-fgColor-link { + color: var(--fgColor-link); +} + +.tw-group.show-line-numbers .group-\[\.show-line-numbers\]\:tw-text-fgColor-link { + color: var(--fgColor-link); +} + .aria-selected\:tw-border-b-4[aria-selected="true"] { border-bottom-width: 4px; } diff --git a/assets/data/cdn/jsdelivr.yml b/assets/data/cdn/jsdelivr.yml index 95ccc6656..ff175bb7f 100644 --- a/assets/data/cdn/jsdelivr.yml +++ b/assets/data/cdn/jsdelivr.yml @@ -12,8 +12,6 @@ libFiles: aplayerJS: aplayer@1.10.1/dist/APlayer.min.js # autocomplete.js@0.38.0 https://github.com/algolia/autocomplete.js autocompleteJS: autocomplete.js@0.38.0/dist/autocomplete.min.js - # clipboard.js@2.0.8 https://github.com/zenorocha/clipboard.js - clipboardJS: clipboard@2.0.8/dist/clipboard.min.js # cookieconsent@3.1.1 https://github.com/osano/cookieconsent cookieconsentCSS: cookieconsent@3.1.1/build/cookieconsent.min.css cookieconsentJS: cookieconsent@3.1.1/build/cookieconsent.min.js diff --git a/assets/js/shims/clipboard.js b/assets/js/shims/clipboard.js deleted file mode 100644 index ccd92aa2c..000000000 --- a/assets/js/shims/clipboard.js +++ /dev/null @@ -1 +0,0 @@ -export default window.ClipboardJS diff --git a/assets/js/theme.js b/assets/js/theme.ts similarity index 84% rename from assets/js/theme.js rename to assets/js/theme.ts index 79e1dd6e2..eb488d8c2 100644 --- a/assets/js/theme.js +++ b/assets/js/theme.ts @@ -1,6 +1,13 @@ +export {}; + +// TODO: add more global states to the window object +declare global { + interface Window { isDark: boolean; } +} + + /* eslint-disable no-new */ /* eslint-disable no-undef */ -// import ClipboardJS from 'clipboard' const Tablesort = require('tablesort') // const autocomplete = require('autocomplete.js') @@ -419,78 +426,6 @@ function initLightGallery () { } } -function initHighlight () { - forEach(document.querySelectorAll('.highlight > pre.chroma'), $preChroma => { - const $chroma = document.createElement('div') - $chroma.className = $preChroma.className - const $table = document.createElement('table') - $chroma.appendChild($table) - const $tbody = document.createElement('tbody') - $table.appendChild($tbody) - const $tr = document.createElement('tr') - $tbody.appendChild($tr) - const $td = document.createElement('td') - $tr.appendChild($td) - $preChroma.parentElement.replaceChild($chroma, $preChroma) - $td.appendChild($preChroma) - }) - forEach(document.querySelectorAll('.highlight > .chroma'), $chroma => { - const $codeElements = $chroma.querySelectorAll('pre.chroma > code') - if ($codeElements.length) { - const $code = $codeElements[$codeElements.length - 1] - const $header = document.createElement('div') - $header.className = 'code-header ' + $code.className.toLowerCase() - const $title = document.createElement('span') - $title.classList.add('code-title') - $title.insertAdjacentHTML('afterbegin', ``) - $title.addEventListener('click', () => { - const content = $chroma.getElementsByClassName('table-wrapper')[0] - if ($chroma.classList.contains('open')) { - content.style.maxHeight = null - } else { - content.style.maxHeight = content.scrollHeight + 'px' - } - $chroma.classList.toggle('open') - }, false) - addEventListener("beforeprint", (event) => { - if ($chroma.classList.contains('open')) { - return; - } - $title.click(); - }); - $header.appendChild($title) - const $ellipses = document.createElement('span') - $ellipses.insertAdjacentHTML('afterbegin', '') - $ellipses.classList.add('ellipses') - $ellipses.addEventListener('click', () => { - $chroma.classList.add('open') - }, false) - $header.appendChild($ellipses) - const $copy = document.createElement('span') - const copyHTML = ``; - const checkHTML = ``; - $copy.insertAdjacentHTML('afterbegin', copyHTML) - $copy.classList.add('copy') - const code = $code.innerText - if (window.config.code.maxShownLines < 0 || code.split('\n').length < window.config.code.maxShownLines + 2) $chroma.classList.add('open') - if (window.config.code.copyTitle) { - $copy.setAttribute('data-clipboard-text', code) - $copy.title = window.config.code.copyTitle - const clipboard = new ClipboardJS($copy) - clipboard.on('success', _e => { - animateCSS($code, 'animate__flash') - $copy.firstElementChild.innerHTML = checkHTML - setTimeout(() => { - $copy.firstElementChild.innerHTML = copyHTML - }, 3000) - }) - $header.appendChild($copy) - } - $chroma.insertBefore($header, $chroma.firstChild) - } - }) -} - function initTable () { forEach(document.querySelectorAll('.content table'), $table => { const $wrapper = document.createElement('div') @@ -763,6 +698,60 @@ function onClickMask () { }, false) } +function initCodeblocks() { + document.querySelectorAll('.code-block').forEach((codeBlock) => { + // the queries are guaranteed to be successful + const titleBar = codeBlock.querySelector('div.code-block-title-bar') as HTMLDivElement; + const chroma = codeBlock.querySelector('code.chroma') as HTMLElement; + const copyCodeButton = codeBlock.querySelector('button.copy-code-button') as HTMLButtonElement; + const copyIcon = copyCodeButton.querySelector('span.copy-icon') as SVGElement; + const checkIcon = copyCodeButton.querySelector('span.check-icon') as SVGElement; + const wrapCodeButton = codeBlock.querySelector('button.wrap-code-button') as HTMLButtonElement; + const toggleLineNumbersButton = codeBlock.querySelector('button.line-number-button') as HTMLButtonElement; + + chroma.style.maxHeight = chroma.scrollHeight + 10 + 'px'; + + // handle expanding and collapsing code blocks + titleBar.addEventListener('click', () => { + codeBlock.classList.toggle('is-open'); + codeBlock.classList.toggle('is-closed'); + }); + + // handle copying code to clipboard + copyCodeButton?.addEventListener('click', () => { + navigator.clipboard.writeText(chroma.innerText); + // toggle icons + copyIcon.style.display = 'none'; + checkIcon.style.display = 'block'; + setTimeout(() => { + copyIcon.style.display = 'block'; + checkIcon.style.display = 'none'; + }, 3000); + }); + + // handle wrapping lines in code blocks + wrapCodeButton?.addEventListener('click', () => { + chroma.style.maxHeight = 'fit-content'; + codeBlock.classList.toggle('is-wrap'); + chroma.style.maxHeight = chroma.scrollHeight + 10 + 'px'; + }); + + toggleLineNumbersButton.addEventListener('click', () => { + codeBlock.classList.toggle('show-line-numbers'); + }); + + addEventListener("beforeprint", (_) => { + if (codeBlock.classList.contains('is-closed')) { + titleBar.click(); + } + if (!codeBlock.classList.contains('is-wrap')) { + wrapCodeButton.click(); + } + }); + }); +} + + function init () { window.isDark = document.body.getAttribute('theme') !== 'light' window.newScrollTop = getScrollTop() @@ -776,9 +765,9 @@ function init () { initSelectTheme() initMeta() initSearch() + initCodeblocks() initDetails() initLightGallery() - initHighlight() initTable() initTypeit() initMapbox() diff --git a/assets/lib/clipboard/clipboard.min.js b/assets/lib/clipboard/clipboard.min.js deleted file mode 100644 index 95f55d7b0..000000000 --- a/assets/lib/clipboard/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.8 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={134:function(t,e,n){"use strict";n.d(e,{default:function(){return r}});var e=n(279),i=n.n(e),e=n(370),a=n.n(e),e=n(817),o=n.n(e);function c(t){return(c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function u(t,e){for(var n=0;n``` to block in multiple lines of code with a language attribute. -{{< highlight markdown >}} +````markdown ```markdown Sample text here... ``` -{{< / highlight >}} +```` The HTML looks like this: @@ -509,7 +509,7 @@ To activate it, simply add the file extension of the language you want to use di For example, to apply syntax highlighting to JavaScript code: -{{< highlight markdown >}} +````markdown {open=true} ```js grunt.initConfig({ assemble: { @@ -530,11 +530,11 @@ grunt.initConfig({ } }; ``` -{{< / highlight >}} +```` The rendered output looks like this: -```js +```js {open=true} grunt.initConfig({ assemble: { options: { @@ -555,9 +555,108 @@ grunt.initConfig({ }; ``` -{{< admonition >}} -[Syntax highlighting page](https://gohugo.io/content-management/syntax-highlighting/) in **Hugo** Docs introduces more about syntax highlighting, including highlight shortcode. -{{< /admonition >}} +You can supply extra options to the code block. + +| Option | Description | +| ------ | ----------- | +| `open` | Whether to expand the code block. The default value is determined by the `maxShownLines` option. | +| `lineNos` | Whether to show line numbers. | +| `wrap` | Whether to wrap lines when they overflow. | +| `title` | Set the title of the code block. | + +Here is an example + +````markdown {open=true} +```go {open=true, lineNos=false, wrap=true, title="main.go"} +package main + +import "fmt" + +// calculateSquares calculates the sum of the squares of the digits of the given number +// and sends the result to the squareop channel. +func calculateSquares(number int, squareop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit + number /= 10 + } + squareop <- sum +} + +// calculateCubes calculates the sum of the cubes of the digits of the given number +// and sends the result to the cubeop channel. +func calculateCubes(number int, cubeop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit * digit + number /= 10 + } + cubeop <- sum +} + +func main() { + number := 589 + sqrch := make(chan int) + cubech := make(chan int) + + // Start two goroutines to calculate the sum of squares and cubes of the digits. + go calculateSquares(number, sqrch) + go calculateCubes(number, cubech) + + // Receive the results from the channels and add them. + squares, cubes := <-sqrch, <-cubech + fmt.Println("Final result", squares+cubes) +} +``` +```` + +The rendered output looks like this: + +```go {open=true, lineNos=false, wrap=true, title="main.go"} +package main + +import "fmt" + +// calculateSquares calculates the sum of the squares of the digits of the given number +// and sends the result to the squareop channel. +func calculateSquares(number int, squareop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit + number /= 10 + } + squareop <- sum +} + +// calculateCubes calculates the sum of the cubes of the digits of the given number +// and sends the result to the cubeop channel. +func calculateCubes(number int, cubeop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit * digit + number /= 10 + } + cubeop <- sum +} + +func main() { + number := 589 + sqrch := make(chan int) + cubech := make(chan int) + + // Start two goroutines to calculate the sum of squares and cubes of the digits. + go calculateSquares(number, sqrch) + go calculateCubes(number, cubech) + + // Receive the results from the channels and add them. + squares, cubes := <-sqrch, <-cubech + fmt.Println("Final result", squares+cubes) +} +``` ## Tables diff --git a/exampleSite/content/posts/basic-markdown-syntax/index.zh-cn.md b/exampleSite/content/posts/basic-markdown-syntax/index.zh-cn.md index cf947700e..7c0332086 100644 --- a/exampleSite/content/posts/basic-markdown-syntax/index.zh-cn.md +++ b/exampleSite/content/posts/basic-markdown-syntax/index.zh-cn.md @@ -487,11 +487,11 @@ odio non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac 使用 "围栏" ``` 来生成一段带有语言属性的代码块. -{{< highlight markdown >}} +````markdown ```markdown Sample text here... ``` -{{< / highlight >}} +```` 输出的 HTML 看起来像这样: @@ -510,7 +510,7 @@ Sample text here... 例如, 在以下 JavaScript 代码中应用语法高亮: -{{< highlight markdown >}} +````markdown ```js grunt.initConfig({ assemble: { @@ -531,7 +531,7 @@ grunt.initConfig({ } }; ``` -{{< / highlight >}} +```` 呈现的输出效果如下: @@ -556,10 +556,108 @@ grunt.initConfig({ }; ``` -{{< admonition >}} -**Hugo** 文档中的 [语法高亮页面](https://gohugo.io/content-management/syntax-highlighting/) 介绍了有关语法高亮的更多信息, -包括语法高亮的 shortcode. -{{< /admonition >}} +您可以通过以下选项来自定义你的代码块。 + +| 选项 | 描述 | +| ------ | ----------- | +| `open` | 是否展开代码块。默认值由 `maxShownLines` 决定。 | +| `lineNos` | 是否显示行数 | +| `wrap` | 长度溢出是否换行。 | +| `title` | 自定义代码块的标题。 | + +以下是一个例子 + +````markdown {open=true} +```go {open=true, lineNos=false, wrap=true, title="main.go"} +package main + +import "fmt" + +// calculateSquares calculates the sum of the squares of the digits of the given number +// and sends the result to the squareop channel. +func calculateSquares(number int, squareop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit + number /= 10 + } + squareop <- sum +} + +// calculateCubes calculates the sum of the cubes of the digits of the given number +// and sends the result to the cubeop channel. +func calculateCubes(number int, cubeop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit * digit + number /= 10 + } + cubeop <- sum +} + +func main() { + number := 589 + sqrch := make(chan int) + cubech := make(chan int) + + // Start two goroutines to calculate the sum of squares and cubes of the digits. + go calculateSquares(number, sqrch) + go calculateCubes(number, cubech) + + // Receive the results from the channels and add them. + squares, cubes := <-sqrch, <-cubech + fmt.Println("Final result", squares+cubes) +} +``` +```` + +输出的效果如下: + +```go {open=true, lineNos=false, wrap=true, title="main.go"} +package main + +import "fmt" + +// calculateSquares calculates the sum of the squares of the digits of the given number +// and sends the result to the squareop channel. +func calculateSquares(number int, squareop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit + number /= 10 + } + squareop <- sum +} + +// calculateCubes calculates the sum of the cubes of the digits of the given number +// and sends the result to the cubeop channel. +func calculateCubes(number int, cubeop chan int) { + sum := 0 + for number != 0 { + digit := number % 10 + sum += digit * digit * digit + number /= 10 + } + cubeop <- sum +} + +func main() { + number := 589 + sqrch := make(chan int) + cubech := make(chan int) + + // Start two goroutines to calculate the sum of squares and cubes of the digits. + go calculateSquares(number, sqrch) + go calculateCubes(number, cubech) + + // Receive the results from the channels and add them. + squares, cubes := <-sqrch, <-cubech + fmt.Println("Final result", squares+cubes) +} +``` ## 表格 diff --git a/exampleSite/content/posts/tests/codeblock-tests/index.en.md b/exampleSite/content/posts/tests/codeblock-tests/index.en.md new file mode 100644 index 000000000..beab35881 --- /dev/null +++ b/exampleSite/content/posts/tests/codeblock-tests/index.en.md @@ -0,0 +1,84 @@ +--- +title: "Codeblock Tests" +subtitle: "" +date: 2024-03-26T12:27:57+01:00 +lastmod: 2024-04-26T12:27:57+01:00 +draft: true +description: "Test codeblock rendering" +categories: [Tests] +authors: [PCloud] +hiddenFromHomePage: true +hiddenFromSearch: true +--- + + + +```cpp +#include +int main() +{ + std::cout << "Hello world!" << std::endl; + return 0; +} +``` + +```cpp +#include +int main() +{ + std::cout << "Hello world!" << std::endl; + return 0; +} +``` + +``` +I2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0KI2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0KI2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0KI2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0K +I2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0K +``` + +```{wrap=true} +I2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0KI2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0KI2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0KI2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0K +I2luY2x1ZGUgPGlvc3RyZWFtPgppbnQgbWFpbigpCnsKICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8gd29ybGQhIiA8PCBlbmRsOwogICAgcmV0dXJuIDA7Cn0K +``` + +```cpp {title="main.cpp"} +#include +int main() +{ + std::cout << "Hello world!" << std::endl; + return 0; +} +``` + +```cpp {open=false} +#include +int main() +{ + std::cout << "Hello world!" << std::endl; + return 0; +} +``` + +```cpp {lineNos=false} +#include +int main() +{ + std::cout << "Hello world!" << std::endl; + return 0; +} +``` + +```cpp {lineNos=false} +#include +int main() +{ + std::cout << "Hello world!" << std::endl; + std::cout << "Hello world!" << std::endl; + std::cout << "Hello world!" << std::endl; + std::cout << "Hello world!" << std::endl; + std::cout << "Hello world!" << std::endl; + std::cout << "Hello world!" << std::endl; + std::cout << "Hello world!" << std::endl; + return 0; +} +``` \ No newline at end of file diff --git a/exampleSite/content/posts/theme-documentation-basics/index.en.md b/exampleSite/content/posts/theme-documentation-basics/index.en.md index 2b50d17a3..50303a821 100644 --- a/exampleSite/content/posts/theme-documentation-basics/index.en.md +++ b/exampleSite/content/posts/theme-documentation-basics/index.en.md @@ -511,8 +511,6 @@ Please open the code block below to view the complete sample configuration {{< f mhchem = true # {{< version 0.2.0 >}} Code config [params.page.code] - # whether to show the copy button of the code block - copy = true # the maximum number of lines of displayed code by default maxShownLines = 10 # {{< version 0.2.14 >}} Table config diff --git a/exampleSite/content/posts/theme-documentation-basics/index.zh-cn.md b/exampleSite/content/posts/theme-documentation-basics/index.zh-cn.md index a35ff818d..fe3ec6fde 100644 --- a/exampleSite/content/posts/theme-documentation-basics/index.zh-cn.md +++ b/exampleSite/content/posts/theme-documentation-basics/index.zh-cn.md @@ -502,8 +502,6 @@ optimizeImages = true auto = true # {{< version 0.2.0 >}} 代码配置 [params.page.code] - # 是否显示代码块的复制按钮 - copy = true # 默认展开显示的代码行数 maxShownLines = 10 # {{< version 0.2.14 >}} 表格配置 diff --git a/layouts/_default/_markup/render-codeblock.html b/layouts/_default/_markup/render-codeblock.html new file mode 100644 index 000000000..435928f09 --- /dev/null +++ b/layouts/_default/_markup/render-codeblock.html @@ -0,0 +1,112 @@ +{{ $result := transform.HighlightCodeBlock . }} +{{- $id := dict "Scratch" .Page.Scratch | partial "function/id.html" -}} +{{- $title := .Attributes.title | default .Type | default "text" -}} +{{- $lineNos := cond (eq .Options.linenos false) "" "show-line-numbers" -}} +{{- $lines := len (split .Inner "\n") -}} +{{- $maxShownLines := .Page.Params.code.maxshownlines | default site.Params.page.code.maxshownlines -}} +{{- $open := "is-open" -}} +{{- if eq .Attributes.open nil -}} + {{- $open = cond (gt $lines $maxShownLines) "is-closed" "is-open" -}} +{{- else -}} + {{- $open = cond (eq .Attributes.open false) "is-closed" "is-open" -}} +{{- end -}} +{{- $wrap := cond (eq .Attributes.wrap true) "is-wrap" "" -}} + +
+
+ + +
+

{{ $title }}

+
+
+ + + + + + + +
+
+
{{ $result.Inner }}
+
diff --git a/layouts/partials/assets.html b/layouts/partials/assets.html index d07043991..6f756bd3a 100644 --- a/layouts/partials/assets.html +++ b/layouts/partials/assets.html @@ -61,16 +61,6 @@ {{- $config = dict "selector" ".lightgallery" "speed" 400 "hideBarsDelay" 2000 "thumbnail" true "exThumbImage" "data-thumbnail" "thumbWidth" 80 "thumbContHeight" 80 "actualSize" false | dict "lightGallery" | merge $config -}} {{- end -}} -{{- $code := $params.code | default dict -}} -{{- $config = cond (ne $code.maxShownLines nil) $code.maxShownLines 10 | dict "maxShownLines" | dict "code" | merge $config -}} - -{{- /* clipboard.js */ -}} -{{- if ne $code.copy false -}} - {{- $source := $cdn.clipboardJS | default "lib/clipboard/clipboard.min.js" -}} - {{- dict "Source" $source "Fingerprint" $fingerprint | dict "Scratch" .Scratch "Data" | partial "scratch/script.html" -}} - {{- $config = T "copyToClipboard" | dict "copyTitle" | dict "code" | merge $config -}} -{{- end -}} - {{- /* Sharer.js */ -}} {{- if $params.share.enable | and (.Scratch.Get "this").sharer -}} {{- $source := $cdn.sharerJS | default "lib/sharer/sharer.min.js" -}} @@ -265,13 +255,12 @@ {{- $options = dict "minify" true | merge $options -}} {{- $shims := dict -}} {{- $shims = dict "tablesort" "js/shims/tablesort.js" | merge $shims -}} -{{- /* $shims = dict "clipboard" "js/shims/clipboard.js" | merge $shims */ -}} {{- $options = dict "shims" $shims | merge $options -}} {{- if hugo.IsProduction -}} {{- else -}} {{- $options = dict "sourceMap" "inline" | merge $options -}} {{- end -}} -{{- $js := resources.Get "js/theme.js" | js.Build $options -}} +{{- $js := resources.Get "js/theme.ts" | js.Build $options -}} {{- $_ := $js.RelPermalink -}} {{- dict "Link" $js.RelPermalink "Fingerprint" $fingerprint "Defer" true | dict "Scratch" .Scratch "Data" | partial "scratch/script.html" -}} diff --git a/package-lock.json b/package-lock.json index 5984e83b6..a727638b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "artalk": "^2.8.5", "atomic-algolia": "^0.3.19", "autocomplete.js": "^0.38.1", - "clipboard": "^2.0.11", "cookieconsent": "^3.1.1", "echarts": "^5.5.0", "katex": "^0.16.10", @@ -3015,16 +3014,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/clipboard": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", - "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", - "dependencies": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, "node_modules/cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -3484,11 +3473,6 @@ "node": ">=0.4.0" } }, - "node_modules/delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -4684,14 +4668,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "dependencies": { - "delegate": "^3.1.2" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -6400,11 +6376,6 @@ "node": ">=12.0.0" } }, - "node_modules/select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" - }, "node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -6864,11 +6835,6 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "node_modules/tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" - }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/package.json b/package.json index 3d82d0b1c..0ad13c0d8 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "artalk": "^2.8.5", "atomic-algolia": "^0.3.19", "autocomplete.js": "^0.38.1", - "clipboard": "^2.0.11", "cookieconsent": "^3.1.1", "echarts": "^5.5.0", "katex": "^0.16.10", diff --git a/tailwind.config.js b/tailwind.config.js index bc554a6aa..4ea3f0355 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -22,6 +22,10 @@ module.exports = { } } }, + safelist: [ + 'tw-text-wrap', + '!tw-max-h-0', + ], plugins: [ require('tailwindcss-aria-attributes') ]