Compare commits

..

No commits in common. "75a864db8c06b1efe256f6e5eebb70e9ad4cfdd2" and "6dce77714e35267fa8a4bb6c8123b0b30b62cae6" have entirely different histories.

7 changed files with 158 additions and 175 deletions

View File

@ -9,9 +9,6 @@ import { Tooltip } from "./Tooltip.mjs";
import { TopbarButton } from "./TopbarButton.mjs"; import { TopbarButton } from "./TopbarButton.mjs";
import { Select } from "../menu/islands/Select.mjs"; import { Select } from "../menu/islands/Select.mjs";
const topbarId = "e0700ce3-a9ae-45f5-92e5-610ded0e348d",
coreId = "0f0bf8b6-eae6-4273-b307-8fc43f2ee082";
// note: these islands are not reusable. // note: these islands are not reusable.
// panel views can be added via addPanelView, // panel views can be added via addPanelView,
// do not instantiate additional panels // do not instantiate additional panels
@ -138,7 +135,8 @@ function Panel({
</aside> </aside>
</div>`; </div>`;
const topbarFavorite = ".notion-topbar .notion-topbar-favorite-button", const topbarId = "e0700ce3-a9ae-45f5-92e5-610ded0e348d",
topbarFavorite = ".notion-topbar .notion-topbar-favorite-button",
$topbarToggle = html`<${TopbarButton} $topbarToggle = html`<${TopbarButton}
aria-label="Toggle side panel" aria-label="Toggle side panel"
icon="panel-right" icon="panel-right"
@ -209,11 +207,7 @@ function Panel({
const animationState = { ...closedWidth }, const animationState = { ...closedWidth },
animate = ($target, keyframes) => { animate = ($target, keyframes) => {
const opts = { const opts = { fill: "forwards", duration: transitionDuration, easing: "ease" };
fill: "forwards",
duration: transitionDuration,
easing: "ease",
};
$target.animate(keyframes, opts); $target.animate(keyframes, opts);
}, },
animatePanel = (to) => { animatePanel = (to) => {
@ -284,11 +278,12 @@ function Panel({
// hovering over the peek trigger will temporarily // hovering over the peek trigger will temporarily
// pop out an interactive preview of the panel // pop out an interactive preview of the panel
let _peekDebounce, _peekPanelOnHover; let _peekDebounce, _peekPanelOnHover;
const $peekTrigger = html`<div const coreId = "0f0bf8b6-eae6-4273-b307-8fc43f2ee082",
class="absolute z-10 right-0 h-[calc(100vh-120px)] bottom-[60px] w-[96px] $peekTrigger = html`<div
class="absolute z-10 right-0 h-[calc(100vh-120px)] bottom-[60px] w-[96px]
group-[&[data-peeked]]/panel:(w-[calc(var(--panel--width,0)+8px)]) group-[&[data-peeked]]/panel:(w-[calc(var(--panel--width,0)+8px)])
group-[&[data-pinned]]/panel:(w-[calc(var(--panel--width,0)+8px)])" group-[&[data-pinned]]/panel:(w-[calc(var(--panel--width,0)+8px)])"
></div>`; ></div>`;
modDatabase(coreId).then(async (db) => { modDatabase(coreId).then(async (db) => {
_peekPanelOnHover = await db.get("peekPanelOnHover"); _peekPanelOnHover = await db.get("peekPanelOnHover");
if (_peekPanelOnHover) $panel.prepend($peekTrigger); if (_peekPanelOnHover) $panel.prepend($peekTrigger);

View File

@ -5,14 +5,11 @@
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
function LineNumbers() { function LineNumber({ number, height, ...props }) {
const { html } = globalThis.__enhancerApi; const { html } = globalThis.__enhancerApi;
return html`<div return html`<span class="block text-right" style="height:${height}px">
class="notion-enhancer--line-numbers flex-grow ${number}
text-([85%] [var(--theme--fg-secondary)] right) </span>`;
font-[var(--font--code)] pt-[34px] pb-[32px]
overflow-hidden"
></div>`;
} }
export default async (api, db) => { export default async (api, db) => {
@ -20,75 +17,61 @@ export default async (api, db) => {
numberSingleLines = await db.get("numberSingleLines"), numberSingleLines = await db.get("numberSingleLines"),
lineNumberDecoration = await db.get("lineNumberDecoration"), lineNumberDecoration = await db.get("lineNumberDecoration"),
lineNumbersClass = "notion-enhancer--line-numbers", lineNumbersClass = "notion-enhancer--line-numbers",
codeBlockSelector = ".notion-code-block.line-numbers > .notranslate"; codeBlockSelector = ".notion-code-block.line-numbers";
// get character width in pixels
const getCharWidth = ($elem) => {
const $char = html`<span style="width:1ch"> </span>`;
$elem.append($char);
const charWidth = getComputedStyle($char).getPropertyValue("width");
$char.remove();
return parseFloat(charWidth);
},
// get line width in pixels
getLineWidth = ($elem) =>
parseFloat(getComputedStyle($elem).getPropertyValue("width")) -
parseFloat(getComputedStyle($elem).getPropertyValue("padding-left")) -
parseFloat(getComputedStyle($elem).getPropertyValue("padding-right")),
// get line height in pixels
getLineHeight = ($elem) =>
parseFloat(getComputedStyle($elem).getPropertyValue("line-height")),
// update inline styles without unnecessary dom updates
applyStyles = ($elem, styles) => {
for (const property in styles) {
if ($elem.style[property] === styles[property]) continue;
$elem.style[property] = styles[property];
}
};
const numberLines = () => { const numberLines = () => {
for (const $code of document.querySelectorAll(codeBlockSelector)) { for (const $block of document.querySelectorAll(codeBlockSelector)) {
const $code = $block.lastElementChild,
computedStyles = getComputedStyle($code);
const wrap = $code.style.wordBreak === "break-all", const wrap = $code.style.wordBreak === "break-all",
lines = $code.innerText.split("\n"), lines = $code.innerText.split("\n"),
lineCount = Math.max(lines.length - 1, 1), lineCount = Math.max(lines.length - 1, 1),
lineNumDigits = (Math.log(lineCount) * Math.LOG10E + 1) | 0; lineNumDigits = (Math.log(lineCount) * Math.LOG10E + 1) | 0;
const doUpdate = const update =
$code.dataset.lines !== String(lineCount) || parseInt($block.dataset.lines) !== lineCount ||
$code.dataset.wrap !== String(wrap); $block.dataset.wrap !== String(wrap);
if (!doUpdate) continue; if (!update) continue;
$code.dataset.lines = lineCount; $block.dataset.lines = lineCount;
$code.dataset.wrap = wrap; $block.dataset.wrap = wrap;
// shrink block to allow space for numbers // shrink block to allow space for numbers
const width = `calc(100% - 32px - ${lineNumDigits}ch)`; $block.style.justifyContent = "flex-end";
applyStyles($code.parentElement, { justifyContent: "flex-end" }); $code.style.minWidth = `calc(100% - 32px - ${lineNumDigits}ch)`;
applyStyles($code, { minWidth: width, maxWidth: width }); $code.style.maxWidth = $code.style.minWidth;
// get 1ch in pixels
const $tmp = html`<span style="width:1ch"> </span>`;
$code.append($tmp);
const charWidth = getComputedStyle($tmp).getPropertyValue("width");
$tmp.remove();
// work out height of wrapped lines // work out height of wrapped lines
const lineHeight = getLineHeight($code), const lineWidth =
charsPerLine = Math.floor(getLineWidth($code) / getCharWidth($code)); 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"));
// update line numbers in dom const $numbers = html`<div
let totalHeight = 34; class="${lineNumbersClass} font-[var(--font--code)] flex-grow
$code._$lineNumbers ||= LineNumbers(); text-([85%] [var(--theme--fg-secondary)] right) pt-[34px] pb-[32px]"
></div>`;
for (let i = 1; i <= lineCount; i++) { for (let i = 1; i <= lineCount; i++) {
let $n = $code._$lineNumbers.children[i - 1]; let lineSpan = 1;
if (!$n) { if (wrap) lineSpan = Math.ceil(lines[i - 1].length / charsPerLine);
$n = html`<span class="block text-right">${i}</span>`; $numbers.append(
$code._$lineNumbers.append($n); html`<${LineNumber}
} number=${i}
const height = height=${(lineSpan || 1) * lineHeight}
wrap && lines[i - 1].length > charsPerLine />`
? Math.ceil(lines[i - 1].length / charsPerLine) * lineHeight );
: lineHeight;
applyStyles($n, { height: `${height}px` });
totalHeight += height;
} }
applyStyles($code._$lineNumbers, { height: `${totalHeight}px` });
if (!document.contains($code._$lineNumbers)) const $prev = $block.getElementsByClassName(lineNumbersClass)[0];
$code.before($code._$lineNumbers); $prev ? $prev.replaceWith($numbers) : $block.prepend($numbers);
} }
}; };

View File

@ -1,44 +1,18 @@
/** /**
* notion-enhancer: tweaks * notion-enhancer: tweaks
* (c) 2020 Arecsu
* (c) 2024 1280px * (c) 2024 1280px
* (c) 2020 Arecsu
* (c) 2024 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/) * (c) 2024 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
/* interface */
/* pages */
body[data-tweaks*=",normalisedDatabaseScrolling,"] {
.notion-page-content {
.notion-collection_view-block {
width: 100% !important;
}
.notion-board-view {
margin-left: 0 !important;
margin-right: 0 !important;
}
:is(.notion-collection_view-block, .notion-collection-view-body)
> [style*="padding"] {
padding-left: 0 !important;
padding-right: 0 !important;
min-width: auto !important;
}
}
}
/* typography */
.enhancer--tweak-responsive_breakpoint .enhancer--tweak-responsive_breakpoint
.notion-column_list-block .notion-column_list-block
[style="display: flex;"] [style='display: flex;']
> div { > div {
width: 100% !important; width: 100% !important;
} }
.enhancer--tweak-responsive_breakpoint .enhancer--tweak-responsive_breakpoint .notion-column_list-block [style='display: flex;'] {
.notion-column_list-block
[style="display: flex;"] {
flex-direction: column !important; flex-direction: column !important;
} }
.enhancer--tweak-responsive_breakpoint .notion-app-inner, .enhancer--tweak-responsive_breakpoint .notion-app-inner,
@ -47,6 +21,29 @@ body[data-tweaks*=",normalisedDatabaseScrolling,"] {
--theme--page-padding: calc(48px + env(safe-area-inset-left)); --theme--page-padding: calc(48px + env(safe-area-inset-left));
} }
.enhancer--tweak-normalise_table_scroll
.notion-frame
.notion-page-content
.notion-collection_view-block,
.enhancer--tweak-normalise_table_scroll .notion-peek-renderer .notion-collection_view-block,
.enhancer--tweak-normalise_table_scroll
.notion-page-template-modal
.notion-collection_view-block,
.enhancer--tweak-normalise_table_dscroll .notion-collection-view-body .notion-table-view {
width: 100% !important;
padding: 0 !important;
}
.enhancer--tweak-normalise_table_scroll
.notion-collection_view-block
> [contenteditable]
> .notion-scroller
> [class$='view'][style*='padding'],
.enhancer--tweak-normalise_table_scroll
.notion-collection_view-block
> :first-child[style*='padding-right'] {
padding: 1px !important;
}
.enhancer--tweak-snappy_transitions * { .enhancer--tweak-snappy_transitions * {
animation-duration: 0s !important; animation-duration: 0s !important;
transition-duration: 0s !important; transition-duration: 0s !important;
@ -60,39 +57,26 @@ body[data-tweaks*=",normalisedDatabaseScrolling,"] {
} }
.enhancer--tweak-hide_slash_for_commands [contenteditable]:empty:after { .enhancer--tweak-hide_slash_for_commands [contenteditable]:empty:after {
content: " " !important; content: ' ' !important;
} }
.enhancer--tweak-hide_default_page_icons .enhancer--tweak-hide_default_page_icons
.notion-sidebar .notion-sidebar a > div > div:has(.notion-record-icon svg.page),
a
> div
> div:has(.notion-record-icon svg.page),
.enhancer--tweak-hide_default_page_icons .enhancer--tweak-hide_default_page_icons
.layout .layout a > div > div > div > div:has(.notion-record-icon svg.page) {
a
> div
> div
> div
> div:has(.notion-record-icon svg.page) {
display: none !important; display: none !important;
} }
.enhancer--tweak-thicker_bold .enhancer--tweak-thicker_bold .notion-page-content span[style*='font-weight:600'] {
.notion-page-content
span[style*="font-weight:600"] {
font-weight: 700 !important; font-weight: 700 !important;
} }
.enhancer--tweak-spaced_lines .enhancer--tweak-spaced_lines .notion-page-content .notion-selectable.notion-text-block {
.notion-page-content
.notion-selectable.notion-text-block {
line-height: 1.65 !important; line-height: 1.65 !important;
margin-top: 0.75em !important; margin-top: 0.75em !important;
} }
.enhancer--tweak-condensed_bullets .enhancer--tweak-condensed_bullets .notion-selectable.notion-bulleted_list-block {
.notion-selectable.notion-bulleted_list-block {
margin-top: -1.5px !important; margin-top: -1.5px !important;
margin-bottom: -1.5px !important; margin-bottom: -1.5px !important;
} }
@ -101,12 +85,12 @@ body[data-tweaks*=",normalisedDatabaseScrolling,"] {
border-bottom: none !important; border-bottom: none !important;
} }
.enhancer--tweak-bracketed_links .notion-link-token:before { .enhancer--tweak-bracketed_links .notion-link-token:before {
content: "[["; content: '[[';
opacity: 0.7; opacity: 0.7;
transition: opacity 100ms ease-in; transition: opacity 100ms ease-in;
} }
.enhancer--tweak-bracketed_links .notion-link-token:after { .enhancer--tweak-bracketed_links .notion-link-token:after {
content: "]]"; content: ']]';
opacity: 0.7; opacity: 0.7;
transition: opacity 100ms ease-in; transition: opacity 100ms ease-in;
} }
@ -118,42 +102,32 @@ body[data-tweaks*=",normalisedDatabaseScrolling,"] {
.enhancer--tweak-accented_links .notion-link-token { .enhancer--tweak-accented_links .notion-link-token {
color: var(--theme--accent_blue) !important; color: var(--theme--accent_blue) !important;
} }
.enhancer--tweak-accented_links .enhancer--tweak-accented_links .notion-link-token span[style*='border-bottom:0.05em'] {
.notion-link-token
span[style*="border-bottom:0.05em"] {
opacity: 1 !important; opacity: 1 !important;
border-color: var(--theme--accent_blue) !important; border-color: var(--theme--accent_blue) !important;
} }
.enhancer--tweak-quotation_marks .enhancer--tweak-quotation_marks
.notion-quote-block .notion-quote-block
[style*="border-left: 3px solid currentcolor;"] { [style*='border-left: 3px solid currentcolor;'] {
position: relative; position: relative;
padding-left: 24px !important; padding-left: 24px !important;
padding-right: 18px !important; padding-right: 18px !important;
} }
.enhancer--tweak-quotation_marks .enhancer--tweak-quotation_marks .notion-quote-block [placeholder='Empty quote']::before,
.notion-quote-block .enhancer--tweak-quotation_marks .notion-quote-block [placeholder='Empty quote']::after {
[placeholder="Empty quote"]::before,
.enhancer--tweak-quotation_marks
.notion-quote-block
[placeholder="Empty quote"]::after {
font-family: Georgia, serif; font-family: Georgia, serif;
font-size: 24px; font-size: 24px;
font-weight: bold; font-weight: bold;
position: absolute; position: absolute;
} }
.enhancer--tweak-quotation_marks .enhancer--tweak-quotation_marks .notion-quote-block [placeholder='Empty quote']::before {
.notion-quote-block content: '\201C';
[placeholder="Empty quote"]::before {
content: "\201C";
left: 8px; left: 8px;
top: -2px; top: -2px;
} }
.enhancer--tweak-quotation_marks .enhancer--tweak-quotation_marks .notion-quote-block [placeholder='Empty quote']::after {
.notion-quote-block content: '\201D';
[placeholder="Empty quote"]::after {
content: "\201D";
right: 2px; right: 2px;
bottom: -2px; bottom: -2px;
} }

View File

@ -1,17 +1,56 @@
/** /**
* notion-enhancer: tweaks * notion-enhancer: tweaks
* (c) 2024 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/) * (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
const tweaksId = "5174a483-c88d-4bf8-a95f-35cd330b76e2"; 'use strict';
export default async (api, db) => {
const { getMods } = api,
[{ options }] = await getMods((mod) => mod.id === tweaksId),
tweaks = options.filter((opt) => opt.key).map((opt) => opt.key);
// inc. leading & trailing comma for selectors (see client.css) export default async function ({ web }, db) {
let enabled = ","; const cssInsert = await db.get(['insert.css']);
for (const tweak of tweaks) if (await db.get(tweak)) enabled += tweak + ","; if (cssInsert?.filename) {
document.body.dataset.tweaks = enabled; document.head.append(
}; web.html`<style id="enhancer--tweak-${cssInsert.filename}">${cssInsert.content}</style>`
);
}
const responsiveBreakpointPx = +(await db.get(['tweak.responsive_breakpoint_px'])),
responsiveBreakpointPercent =
screen.width * 0.01 * (await db.get(['tweak.responsive_breakpoint_percent'])),
addResponsiveBreakpoint = () => {
document.body.classList.remove('enhancer--tweak-responsive_breakpoint');
if (
window.innerWidth <= responsiveBreakpointPx ||
window.innerWidth <= responsiveBreakpointPercent
) {
document.body.classList.add('enhancer--tweak-responsive_breakpoint');
}
};
addEventListener('resize', addResponsiveBreakpoint);
addResponsiveBreakpoint();
const tweaks = [
'full_width_pages',
'normalise_table_scroll',
'hide_help',
'hide_slash_for_commands',
'hide_default_page_icons',
'snappy_transitions',
'thicker_bold',
'spaced_lines',
'condensed_bullets',
'bracketed_links',
'accented_links',
'quotation_marks',
];
for (const tweak of tweaks) {
if (await db.get([`tweak.${tweak}`])) {
document.body.classList.add(`enhancer--tweak-${tweak}`);
}
}
const imgAlignment = await db.get(['tweak.img_alignment']);
if (imgAlignment !== 'center') {
document.body.classList.add(`enhancer--tweak-img_alignment-${imgAlignment}`);
}
}

View File

@ -59,9 +59,9 @@
}, },
{ {
"type": "toggle", "type": "toggle",
"key": "normalisedDatabaseScrolling", "key": "normalisedTableScrolling",
"description": "Forces horizontally scrollable inline tables to respect the width and padding of a page when they overflow. Enabling this is recommended if you are using panel mods, otherwise databases may overflow.", "description": "Forces horizontally scrollable inline tables to respect the width and padding of a page when they overflow.",
"value": true "value": false
}, },
{ {
"type": "number", "type": "number",
@ -130,7 +130,5 @@
"description": "Changes the default horizontal alignment of images embedded within pages. Note that this replaces Notion's built-in central alignment, i.e. setting this to left or right will remove the option to centre images entirely.", "description": "Changes the default horizontal alignment of images embedded within pages. Note that this replaces Notion's built-in central alignment, i.e. setting this to left or right will remove the option to centre images entirely.",
"values": ["Centre", "Left", "Right"] "values": ["Centre", "Left", "Right"]
} }
], ]
"clientStyles": ["client.css"],
"clientScripts": ["client.mjs"]
} }

View File

@ -6,13 +6,12 @@
"use strict"; "use strict";
const coreId = "0f0bf8b6-eae6-4273-b307-8fc43f2ee082", const isElectron = () => {
isElectron = () => { try {
try { return typeof module !== "undefined";
return typeof module !== "undefined"; } catch {}
} catch {} return false;
return false; };
};
if (isElectron()) { if (isElectron()) {
require("./api/system.js"); require("./api/system.js");
@ -39,8 +38,8 @@ if (isElectron()) {
// register user-provided javascript for execution in-app // register user-provided javascript for execution in-app
if (target === ".webpack/renderer/tab_browser_view/preload.js") { if (target === ".webpack/renderer/tab_browser_view/preload.js") {
const db = await modDatabase(coreId), const { webFrame } = require("electron"),
{ webFrame } = require("electron"), db = await modDatabase("0f0bf8b6-eae6-4273-b307-8fc43f2ee082"),
customScript = (await db.get("customScript"))?.content; customScript = (await db.get("customScript"))?.content;
if (customScript) webFrame.executeJavaScript(customScript); if (customScript) webFrame.executeJavaScript(customScript);
} }
@ -53,12 +52,8 @@ if (isElectron()) {
const db = await modDatabase(mod.id); const db = await modDatabase(mod.id);
for (let [scriptTarget, script] of mod.electronScripts ?? []) { for (let [scriptTarget, script] of mod.electronScripts ?? []) {
if (target !== scriptTarget) continue; if (target !== scriptTarget) continue;
try { script = require(`./${mod._src}/${script}`);
script = require(`./${mod._src}/${script}`); script(__getApi(), db, __exports, __eval);
script(__getApi(), db, __exports, __eval);
} catch (err) {
console.error(err);
}
} }
} }
}; };

View File

@ -72,8 +72,7 @@ export default (async () => {
Promise.resolve(isCore || API_LOADED) Promise.resolve(isCore || API_LOADED)
.then(() => import(enhancerUrl(`${mod._src}/${script}`))) .then(() => import(enhancerUrl(`${mod._src}/${script}`)))
.then((script) => script.default(globalThis.__enhancerApi, db)) .then((script) => script.default(globalThis.__enhancerApi, db))
.then(() => !isCore || globalThis.__enhancerApi.onReady?.()) .then(() => !isCore || globalThis.__enhancerApi.onReady?.());
.catch((err) => console.error(err));
} }
} }