mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-09 15:09:02 +00:00
extension: code line numbers
This commit is contained in:
parent
6d40349389
commit
b294964b26
30
repo/code-line-numbers/app.css
Normal file
30
repo/code-line-numbers/app.css
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* code line numbers
|
||||||
|
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (c) 2020 CloudHill
|
||||||
|
* under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
.notion-code-block.line-numbers {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-numbered {
|
||||||
|
padding-left: 48px !important;
|
||||||
|
}
|
||||||
|
#code-line-numbers {
|
||||||
|
font-size: var(--theme--font_code-size);
|
||||||
|
font-family: var(--theme--font_code);
|
||||||
|
color: var(--theme--text_ui_info);
|
||||||
|
background: var(--theme--code-background);
|
||||||
|
text-align: right;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: calc(100% - 48px);
|
||||||
|
padding-right: 18px;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
#code-line-numbers:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
63
repo/code-line-numbers/client.css
Normal file
63
repo/code-line-numbers/client.css
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer: code line numbers
|
||||||
|
* (c) 2020 CloudHill <rl.cloudhill@gmail.com> (https://github.com/CloudHill)
|
||||||
|
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
.notion-code-block.line-numbers {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.code_line_numbers--plain:not(:empty) + div,
|
||||||
|
.code_line_numbers--background:not(:empty) + div,
|
||||||
|
.code_line_numbers--border:not(:empty) + div {
|
||||||
|
padding-left: 64px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code_line_numbers--plain,
|
||||||
|
.code_line_numbers--background,
|
||||||
|
.code_line_numbers--border {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: calc(100% - 64px);
|
||||||
|
top: 34px;
|
||||||
|
bottom: 32px;
|
||||||
|
padding-right: 27px;
|
||||||
|
|
||||||
|
font-size: 85%;
|
||||||
|
font-family: var(--theme--font_code);
|
||||||
|
text-align: right;
|
||||||
|
line-height: 1.5;
|
||||||
|
opacity: 0.8;
|
||||||
|
color: var(--theme--text_secondary);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.code_line_numbers--plain:empty,
|
||||||
|
.code_line_numbers--background:empty,
|
||||||
|
.code_line_numbers--border:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.code_line_numbers--background::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 7.25px;
|
||||||
|
width: calc(100% - 27px);
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
background-color: var(--theme--bg);
|
||||||
|
border-radius: 4px;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
.code_line_numbers--border::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: calc(100% - 52px);
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
background-color: var(--theme--ui_divider);
|
||||||
|
}
|
62
repo/code-line-numbers/client.mjs
Normal file
62
repo/code-line-numbers/client.mjs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer: code line numbers
|
||||||
|
* (c) 2020 CloudHill <rl.cloudhill@gmail.com> (https://github.com/CloudHill)
|
||||||
|
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (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`<span></span>`;
|
||||||
|
|
||||||
|
const numberCodeBlock = ($codeBlock) => {
|
||||||
|
const $numbers =
|
||||||
|
$codeBlock.querySelector(`.${numbersClass}`) ||
|
||||||
|
web.html`<span class="${numbersClass}">1</span>`;
|
||||||
|
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.at(-1) === '') 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];
|
||||||
|
$codeBlock.lastElementChild.append($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]);
|
||||||
|
}
|
113
repo/code-line-numbers/mod.js
Normal file
113
repo/code-line-numbers/mod.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* code line numbers
|
||||||
|
* (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (c) 2020 CloudHill
|
||||||
|
* under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { createElement } = require('../../pkg/helpers.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
id: 'd61dc8a7-b195-465b-935f-53eea9efe74e',
|
||||||
|
tags: ['extension'],
|
||||||
|
name: 'code line numbers',
|
||||||
|
desc: 'adds line numbers to code blocks.',
|
||||||
|
version: '1.2.0',
|
||||||
|
author: 'CloudHill',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
key: 'single_lined',
|
||||||
|
label: 'show line numbers on single-lined code blocks',
|
||||||
|
type: 'toggle',
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hacks: {
|
||||||
|
'renderer/preload.js'(store, __exports) {
|
||||||
|
document.addEventListener('readystatechange', (event) => {
|
||||||
|
if (document.readyState !== 'complete') return false;
|
||||||
|
let queue = [];
|
||||||
|
const observer = new MutationObserver((list, observer) => {
|
||||||
|
if (!queue.length) requestAnimationFrame(() => handle(queue));
|
||||||
|
queue.push(...list);
|
||||||
|
});
|
||||||
|
observer.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver((list, observer) => number(list[0].target));
|
||||||
|
|
||||||
|
function handle(list) {
|
||||||
|
queue = [];
|
||||||
|
for (let { addedNodes, target } of list) {
|
||||||
|
const block =
|
||||||
|
target.querySelector('.line-numbers.notion-code-block') ||
|
||||||
|
(addedNodes[0]?.classList?.contains('.notion-code-block') &&
|
||||||
|
addedNodes[0].querySelector('.line-numbers.notion-code-block'));
|
||||||
|
|
||||||
|
if (block) {
|
||||||
|
if (block.dataset.numbered) return;
|
||||||
|
number(block);
|
||||||
|
block.dataset.numbered = true;
|
||||||
|
resizeObserver.observe(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function number(block) {
|
||||||
|
let codeLineNumbers = '';
|
||||||
|
|
||||||
|
let numbers = block.querySelector('#code-line-numbers');
|
||||||
|
if (!numbers) {
|
||||||
|
numbers = createElement('<span id="code-line-numbers"></span>');
|
||||||
|
|
||||||
|
// set size
|
||||||
|
const blockStyle = window.getComputedStyle(block.children[0]);
|
||||||
|
numbers.style.top = blockStyle.paddingTop;
|
||||||
|
numbers.style.bottom = blockStyle.paddingBottom;
|
||||||
|
|
||||||
|
block.append(numbers);
|
||||||
|
|
||||||
|
// get lineHeight
|
||||||
|
const temp = createElement('<span>A</span>');
|
||||||
|
block.firstChild.append(temp);
|
||||||
|
block.lineHeight = temp.getBoundingClientRect().height;
|
||||||
|
temp.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = block.firstChild.innerText.split(/\r\n|\r|\n/);
|
||||||
|
if (lines[lines.length - 1] === '') lines.pop();
|
||||||
|
let lineCounter = 0;
|
||||||
|
const wordWrap = block.firstChild.style.wordBreak === 'break-all';
|
||||||
|
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
lineCounter++;
|
||||||
|
codeLineNumbers += `${lineCounter}\n`;
|
||||||
|
|
||||||
|
if (wordWrap) {
|
||||||
|
const temp = document.createElement('span');
|
||||||
|
temp.innerText = lines[i];
|
||||||
|
block.firstChild.append(temp);
|
||||||
|
const lineHeight = temp.getBoundingClientRect().height;
|
||||||
|
temp.remove();
|
||||||
|
|
||||||
|
for (let j = 1; j < lineHeight / block.lineHeight - 1; j++)
|
||||||
|
codeLineNumbers += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store().single_lined || codeLineNumbers.length > 2) {
|
||||||
|
block.firstChild.classList.add('code-numbered');
|
||||||
|
numbers.innerText = codeLineNumbers || 1;
|
||||||
|
} else {
|
||||||
|
block.firstChild.classList.remove('code-numbered');
|
||||||
|
numbers.innerText = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
35
repo/code-line-numbers/mod.json
Normal file
35
repo/code-line-numbers/mod.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "code line numbers",
|
||||||
|
"id": "d61dc8a7-b195-465b-935f-53eea9efe74e",
|
||||||
|
"version": "0.4.0",
|
||||||
|
"description": "adds line numbers to code blocks.",
|
||||||
|
"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"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -26,6 +26,7 @@
|
|||||||
"bypass-preview",
|
"bypass-preview",
|
||||||
"topbar-icons",
|
"topbar-icons",
|
||||||
"word-counter",
|
"word-counter",
|
||||||
|
"code-line-numbers",
|
||||||
"calendar-scroll",
|
"calendar-scroll",
|
||||||
"weekly-view",
|
"weekly-view",
|
||||||
"collapse-properties",
|
"collapse-properties",
|
||||||
|
Loading…
Reference in New Issue
Block a user