From 6dce77714e35267fa8a4bb6c8123b0b30b62cae6 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 23 May 2024 00:25:04 +1000 Subject: [PATCH] feat(line-numbers): calc size + pos of numbers for wrapped code - fix: #900, #897 - todo: optimise - todo: re-implement styles/opts --- src/extensions/code-line-numbers/client.mjs | 62 -------------- src/extensions/code-line-numbers/mod.json | 36 -------- .../client.css | 4 +- src/extensions/line-numbers/client.mjs | 79 ++++++++++++++++++ .../code-line-numbers.png | Bin src/extensions/line-numbers/mod.json | 34 ++++++++ src/extensions/no-peeking/client.css | 2 +- src/extensions/word-counter/islands/Stat.mjs | 4 +- src/registry.json | 1 + 9 files changed, 119 insertions(+), 103 deletions(-) delete mode 100644 src/extensions/code-line-numbers/client.mjs delete mode 100644 src/extensions/code-line-numbers/mod.json rename src/extensions/{code-line-numbers => line-numbers}/client.css (93%) create mode 100644 src/extensions/line-numbers/client.mjs rename src/extensions/{code-line-numbers => line-numbers}/code-line-numbers.png (100%) create mode 100644 src/extensions/line-numbers/mod.json diff --git a/src/extensions/code-line-numbers/client.mjs b/src/extensions/code-line-numbers/client.mjs deleted file mode 100644 index 5072b39..0000000 --- a/src/extensions/code-line-numbers/client.mjs +++ /dev/null @@ -1,62 +0,0 @@ -/** - * notion-enhancer: code line numbers - * (c) 2020 CloudHill (https://github.com/CloudHill) - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -export default async function ({ web }, db) { - const singleLined = await db.get(['single_lined']), - codeBlockSelector = '.notion-code-block.line-numbers', - numbersClass = `code_line_numbers--${await db.get(['style'])}`, - $temp = web.html``; - - const numberCodeBlock = ($codeBlock) => { - const $numbers = - $codeBlock.querySelector(`.${numbersClass}`) || - web.html`1`; - if (!$codeBlock.contains($numbers)) $codeBlock.prepend($numbers); - - const lines = $codeBlock.lastElementChild.innerText.split(/\r\n|\r|\n/), - wordWrap = $codeBlock.lastElementChild.style.wordBreak === 'break-all'; - if (lines.reverse()[0] === '') lines.pop(); - - let lineNumbers = ''; - for (let i = 1; i <= lines.length + 1; i++) { - lineNumbers += `${i}\n`; - if (wordWrap && lines[i - 1]) { - $temp.innerText = lines[i - 1]; - web.render($codeBlock.lastElementChild, $temp); - const height = parseFloat($temp.getBoundingClientRect().height); - $temp.remove(); - for (let j = 1; j < height / 20.4; j++) lineNumbers += '\n'; - } - } - - if (!singleLined && lines.length < 2) lineNumbers = ''; - if ($numbers.innerText !== lineNumbers) $numbers.innerText = lineNumbers; - }, - numberAllCodeBlocks = () => { - for (const $codeBlock of document.querySelectorAll(codeBlockSelector)) { - numberCodeBlock($codeBlock); - } - }, - observeCodeBlocks = (event) => { - const tempEvent = [...event.addedNodes, ...event.removedNodes].includes($temp), - numbersEvent = - event.target.classList.contains(numbersClass) || - [...event.addedNodes, ...event.removedNodes].some(($node) => - $node?.classList?.contains(numbersClass) - ), - codeEvent = event.target.matches(`${codeBlockSelector}, ${codeBlockSelector} *`); - if (tempEvent || numbersEvent || !codeEvent) return; - - let $codeBlock = event.target; - while (!$codeBlock.matches(codeBlockSelector)) $codeBlock = $codeBlock.parentElement; - numberCodeBlock($codeBlock); - }; - - await web.whenReady(); - numberAllCodeBlocks(); - web.addDocumentObserver(observeCodeBlocks, [codeBlockSelector]); -} diff --git a/src/extensions/code-line-numbers/mod.json b/src/extensions/code-line-numbers/mod.json deleted file mode 100644 index 4e9c0d4..0000000 --- a/src/extensions/code-line-numbers/mod.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "code line numbers", - "id": "d61dc8a7-b195-465b-935f-53eea9efe74e", - "version": "0.4.0", - "description": "adds line numbers to code blocks.", - "preview": "code-line-numbers.png", - "tags": ["extension", "usability"], - "authors": [ - { - "name": "CloudHill", - "email": "rh.cloudhill@gmail.com", - "homepage": "https://github.com/CloudHill", - "avatar": "https://avatars.githubusercontent.com/u/54142180" - } - ], - "js": { - "client": ["client.mjs"] - }, - "css": { - "client": ["client.css"] - }, - "options": [ - { - "type": "toggle", - "key": "single_lined", - "label": "number single-lined code blocks", - "value": false - }, - { - "type": "select", - "key": "style", - "label": "line number style", - "values": ["plain", "background", "border"] - } - ] -} diff --git a/src/extensions/code-line-numbers/client.css b/src/extensions/line-numbers/client.css similarity index 93% rename from src/extensions/code-line-numbers/client.css rename to src/extensions/line-numbers/client.css index 5f3a4df..7179f0f 100644 --- a/src/extensions/code-line-numbers/client.css +++ b/src/extensions/line-numbers/client.css @@ -1,7 +1,7 @@ /** - * notion-enhancer: code line numbers + * notion-enhancer: line numbers * (c) 2020 CloudHill (https://github.com/CloudHill) - * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (c) 2024 dragonwocky (https://dragonwocky.me/) * (https://notion-enhancer.github.io/) under the MIT license */ diff --git a/src/extensions/line-numbers/client.mjs b/src/extensions/line-numbers/client.mjs new file mode 100644 index 0000000..18fc09c --- /dev/null +++ b/src/extensions/line-numbers/client.mjs @@ -0,0 +1,79 @@ +/** + * notion-enhancer: line numbers + * (c) 2020 CloudHill (https://github.com/CloudHill) + * (c) 2024 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +function LineNumber({ number, height, ...props }) { + const { html } = globalThis.__enhancerApi; + return html` + ${number} + `; +} + +export default async (api, db) => { + const { html, addMutationListener } = api, + numberSingleLines = await db.get("numberSingleLines"), + lineNumberDecoration = await db.get("lineNumberDecoration"), + lineNumbersClass = "notion-enhancer--line-numbers", + codeBlockSelector = ".notion-code-block.line-numbers"; + + const numberLines = () => { + for (const $block of document.querySelectorAll(codeBlockSelector)) { + const $code = $block.lastElementChild, + computedStyles = getComputedStyle($code); + + const wrap = $code.style.wordBreak === "break-all", + lines = $code.innerText.split("\n"), + lineCount = Math.max(lines.length - 1, 1), + lineNumDigits = (Math.log(lineCount) * Math.LOG10E + 1) | 0; + + const update = + parseInt($block.dataset.lines) !== lineCount || + $block.dataset.wrap !== String(wrap); + if (!update) continue; + $block.dataset.lines = lineCount; + $block.dataset.wrap = wrap; + + // shrink block to allow space for numbers + $block.style.justifyContent = "flex-end"; + $code.style.minWidth = `calc(100% - 32px - ${lineNumDigits}ch)`; + $code.style.maxWidth = $code.style.minWidth; + + // get 1ch in pixels + const $tmp = html` `; + $code.append($tmp); + const charWidth = getComputedStyle($tmp).getPropertyValue("width"); + $tmp.remove(); + + // work out height of wrapped lines + const lineWidth = + parseFloat(computedStyles.getPropertyValue("width")) - + parseFloat(computedStyles.getPropertyValue("padding-left")) - + parseFloat(computedStyles.getPropertyValue("padding-right")), + charsPerLine = Math.floor(lineWidth / parseFloat(charWidth)), + lineHeight = parseFloat(computedStyles.getPropertyValue("line-height")); + + const $numbers = html`
`; + for (let i = 1; i <= lineCount; i++) { + let lineSpan = 1; + if (wrap) lineSpan = Math.ceil(lines[i - 1].length / charsPerLine); + $numbers.append( + html`<${LineNumber} + number=${i} + height=${(lineSpan || 1) * lineHeight} + />` + ); + } + + const $prev = $block.getElementsByClassName(lineNumbersClass)[0]; + $prev ? $prev.replaceWith($numbers) : $block.prepend($numbers); + } + }; + + addMutationListener(codeBlockSelector, numberLines); +}; diff --git a/src/extensions/code-line-numbers/code-line-numbers.png b/src/extensions/line-numbers/code-line-numbers.png similarity index 100% rename from src/extensions/code-line-numbers/code-line-numbers.png rename to src/extensions/line-numbers/code-line-numbers.png diff --git a/src/extensions/line-numbers/mod.json b/src/extensions/line-numbers/mod.json new file mode 100644 index 0000000..959d59a --- /dev/null +++ b/src/extensions/line-numbers/mod.json @@ -0,0 +1,34 @@ +{ + "name": "Line Numbers", + "id": "d61dc8a7-b195-465b-935f-53eea9efe74e", + "version": "0.5.0", + "description": "Adds line numbers to code blocks.", + "tags": ["code-line-numbers"], + "authors": [ + { + "name": "dragonwocky", + "homepage": "https://dragonwocky.me/", + "avatar": "https://dragonwocky.me/avatar.jpg" + }, + { + "name": "CloudHill", + "homepage": "https://github.com/CloudHill", + "avatar": "https://avatars.githubusercontent.com/u/54142180" + } + ], + "options": [ + { + "type": "toggle", + "key": "numberSingleLines", + "description": "Add line numbers to code blocks with only one line.", + "value": true + }, + { + "type": "select", + "key": "lineNumberDecoration", + "description": "Select a decoration style to distinguish line numbers from code block content.", + "values": ["Border", "Background", "None"] + } + ], + "clientScripts": ["client.mjs"] +} diff --git a/src/extensions/no-peeking/client.css b/src/extensions/no-peeking/client.css index fa78408..e95632b 100644 --- a/src/extensions/no-peeking/client.css +++ b/src/extensions/no-peeking/client.css @@ -1,5 +1,5 @@ /** - * notion-enhancer: no-peeking + * notion-enhancer: no peeking * (c) 2021 dragonwocky (https://dragonwocky.me/) * (https://notion-enhancer.github.io/) under the MIT license */ diff --git a/src/extensions/word-counter/islands/Stat.mjs b/src/extensions/word-counter/islands/Stat.mjs index 955166a..4285af6 100644 --- a/src/extensions/word-counter/islands/Stat.mjs +++ b/src/extensions/word-counter/islands/Stat.mjs @@ -1,10 +1,10 @@ /** - * notion-enhancer: word-counter + * notion-enhancer: word counter * (c) 2024 dragonwocky (https://dragonwocky.me/) * (https://notion-enhancer.github.io/) under the MIT license */ -function Stat({ unit, countable, ...props }, ...children) { +function Stat({ unit, countable, ...props }) { const { html } = globalThis.__enhancerApi, $count = html``, $unit = html``, diff --git a/src/registry.json b/src/registry.json index 0a288dd..6ddcc59 100644 --- a/src/registry.json +++ b/src/registry.json @@ -6,6 +6,7 @@ "extensions/scroller", "extensions/outliner", "extensions/word-counter", + "extensions/line-numbers", "extensions/no-peeking", "extensions/focus", "themes/classic-dark"