mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-04 12:49:03 +00:00
chore: add htm/preact to deps
This commit is contained in:
parent
a81a4dda6f
commit
c7b384bc89
@ -11,6 +11,8 @@ import { fileURLToPath } from "node:url";
|
||||
|
||||
const dependencies = {
|
||||
"twind.min.js": "https://cdn.twind.style",
|
||||
"htm+preact.min.js":
|
||||
"https://unpkg.com/htm@3.1.1/preact/standalone.module.js",
|
||||
"lucide.min.js": "https://unpkg.com/lucide@0.104.0/dist/umd/lucide.min.js",
|
||||
"jscolor.min.js":
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.5.1/jscolor.min.js",
|
||||
|
@ -49,7 +49,7 @@ const initDatabase = (namespace) => {
|
||||
},
|
||||
populate: async (obj) => {
|
||||
return new Promise((res, _rej) => {
|
||||
chrome.storage.local.set(obj, () => res(value));
|
||||
chrome.storage.local.set(obj, () => res(obj));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -1,332 +1,332 @@
|
||||
/**
|
||||
* notion-enhancer: api
|
||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||
* (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||
* (https://notion-enhancer.github.io/) under the MIT license
|
||||
*/
|
||||
|
||||
/**
|
||||
* log-based shading of an rgb color, from
|
||||
* https://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors
|
||||
* @param {number} shade - a decimal amount to shade the color.
|
||||
* 1 = white, 0 = the original color, -1 = black
|
||||
* @param {string} color - the rgb color
|
||||
* @returns {string} the shaded color
|
||||
*/
|
||||
export const rgbLogShade = (shade, color) => {
|
||||
const int = parseInt,
|
||||
round = Math.round,
|
||||
[a, b, c, d] = color.split(","),
|
||||
t = shade < 0 ? 0 : shade * 255 ** 2,
|
||||
p = shade < 0 ? 1 + shade : 1 - shade;
|
||||
return (
|
||||
"rgb" +
|
||||
(d ? "a(" : "(") +
|
||||
round((p * int(a[3] == "a" ? a.slice(5) : a.slice(4)) ** 2 + t) ** 0.5) +
|
||||
"," +
|
||||
round((p * int(b) ** 2 + t) ** 0.5) +
|
||||
"," +
|
||||
round((p * int(c) ** 2 + t) ** 0.5) +
|
||||
(d ? "," + d : ")")
|
||||
);
|
||||
};
|
||||
// /**
|
||||
// * log-based shading of an rgb color, from
|
||||
// * https://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors
|
||||
// * @param {number} shade - a decimal amount to shade the color.
|
||||
// * 1 = white, 0 = the original color, -1 = black
|
||||
// * @param {string} color - the rgb color
|
||||
// * @returns {string} the shaded color
|
||||
// */
|
||||
// export const rgbLogShade = (shade, color) => {
|
||||
// const int = parseInt,
|
||||
// round = Math.round,
|
||||
// [a, b, c, d] = color.split(","),
|
||||
// t = shade < 0 ? 0 : shade * 255 ** 2,
|
||||
// p = shade < 0 ? 1 + shade : 1 - shade;
|
||||
// return (
|
||||
// "rgb" +
|
||||
// (d ? "a(" : "(") +
|
||||
// round((p * int(a[3] == "a" ? a.slice(5) : a.slice(4)) ** 2 + t) ** 0.5) +
|
||||
// "," +
|
||||
// round((p * int(b) ** 2 + t) ** 0.5) +
|
||||
// "," +
|
||||
// round((p * int(c) ** 2 + t) ** 0.5) +
|
||||
// (d ? "," + d : ")")
|
||||
// );
|
||||
// };
|
||||
|
||||
/**
|
||||
* pick a contrasting color e.g. for text on a variable color background
|
||||
* using the hsp (perceived brightness) constants from http://alienryderflex.com/hsp.html
|
||||
* @param {number} r - red (0-255)
|
||||
* @param {number} g - green (0-255)
|
||||
* @param {number} b - blue (0-255)
|
||||
* @returns {string} the contrasting rgb color, white or black
|
||||
*/
|
||||
export const rgbContrast = (r, g, b) => {
|
||||
return Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b)) > 165.75
|
||||
? "rgb(0,0,0)"
|
||||
: "rgb(255,255,255)";
|
||||
};
|
||||
// /**
|
||||
// * pick a contrasting color e.g. for text on a variable color background
|
||||
// * using the hsp (perceived brightness) constants from http://alienryderflex.com/hsp.html
|
||||
// * @param {number} r - red (0-255)
|
||||
// * @param {number} g - green (0-255)
|
||||
// * @param {number} b - blue (0-255)
|
||||
// * @returns {string} the contrasting rgb color, white or black
|
||||
// */
|
||||
// export const rgbContrast = (r, g, b) => {
|
||||
// return Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b)) > 165.75
|
||||
// ? "rgb(0,0,0)"
|
||||
// : "rgb(255,255,255)";
|
||||
// };
|
||||
|
||||
let _hotkeyListenersActivated = false,
|
||||
_hotkeyEventListeners = [],
|
||||
_documentObserver,
|
||||
_documentObserverListeners = [];
|
||||
const _documentObserverEvents = [];
|
||||
// let _hotkeyListenersActivated = false,
|
||||
// _hotkeyEventListeners = [],
|
||||
// _documentObserver,
|
||||
// _documentObserverListeners = [];
|
||||
// const _documentObserverEvents = [];
|
||||
|
||||
/**
|
||||
* wait until a page is loaded and ready for modification
|
||||
* @param {array=} selectors - wait for the existence of elements that match these css selectors
|
||||
* @returns {Promise} a promise that will resolve when the page is ready
|
||||
*/
|
||||
export const whenReady = (selectors = []) => {
|
||||
return new Promise((res, _rej) => {
|
||||
const onLoad = () => {
|
||||
const interval = setInterval(isReady, 100);
|
||||
function isReady() {
|
||||
const ready = selectors.every((selector) => document.querySelector(selector));
|
||||
if (!ready) return;
|
||||
clearInterval(interval);
|
||||
res(true);
|
||||
}
|
||||
isReady();
|
||||
};
|
||||
if (document.readyState !== "complete") {
|
||||
document.addEventListener("readystatechange", (_event) => {
|
||||
if (document.readyState === "complete") onLoad();
|
||||
});
|
||||
} else onLoad();
|
||||
});
|
||||
};
|
||||
// /**
|
||||
// * wait until a page is loaded and ready for modification
|
||||
// * @param {array=} selectors - wait for the existence of elements that match these css selectors
|
||||
// * @returns {Promise} a promise that will resolve when the page is ready
|
||||
// */
|
||||
// export const whenReady = (selectors = []) => {
|
||||
// return new Promise((res, _rej) => {
|
||||
// const onLoad = () => {
|
||||
// const interval = setInterval(isReady, 100);
|
||||
// function isReady() {
|
||||
// const ready = selectors.every((selector) => document.querySelector(selector));
|
||||
// if (!ready) return;
|
||||
// clearInterval(interval);
|
||||
// res(true);
|
||||
// }
|
||||
// isReady();
|
||||
// };
|
||||
// if (document.readyState !== "complete") {
|
||||
// document.addEventListener("readystatechange", (_event) => {
|
||||
// if (document.readyState === "complete") onLoad();
|
||||
// });
|
||||
// } else onLoad();
|
||||
// });
|
||||
// };
|
||||
|
||||
/**
|
||||
* parse the current location search params into a usable form
|
||||
* @returns {Map<string, string>} a map of the url search params
|
||||
*/
|
||||
export const queryParams = () => new URLSearchParams(window.location.search);
|
||||
// /**
|
||||
// * parse the current location search params into a usable form
|
||||
// * @returns {Map<string, string>} a map of the url search params
|
||||
// */
|
||||
// export const queryParams = () => new URLSearchParams(window.location.search);
|
||||
|
||||
/**
|
||||
* replace special html characters with escaped versions
|
||||
* @param {string} str
|
||||
* @returns {string} escaped string
|
||||
*/
|
||||
export const escape = (str) =>
|
||||
str
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/'/g, "'")
|
||||
.replace(/"/g, """)
|
||||
.replace(/\\/g, "\");
|
||||
// /**
|
||||
// * replace special html characters with escaped versions
|
||||
// * @param {string} str
|
||||
// * @returns {string} escaped string
|
||||
// */
|
||||
// export const escape = (str) =>
|
||||
// str
|
||||
// .replace(/&/g, "&")
|
||||
// .replace(/</g, "<")
|
||||
// .replace(/>/g, ">")
|
||||
// .replace(/'/g, "'")
|
||||
// .replace(/"/g, """)
|
||||
// .replace(/\\/g, "\");
|
||||
|
||||
/**
|
||||
* a tagged template processor for raw html:
|
||||
* stringifies, minifies, and syntax highlights
|
||||
* @example web.raw`<p>hello</p>`
|
||||
* @returns {string} the processed html
|
||||
*/
|
||||
export const raw = (str, ...templates) => {
|
||||
const html = str
|
||||
.map(
|
||||
(chunk) =>
|
||||
chunk +
|
||||
(["string", "number"].includes(typeof templates[0])
|
||||
? templates.shift()
|
||||
: escape(JSON.stringify(templates.shift(), null, 2) ?? ""))
|
||||
)
|
||||
.join("");
|
||||
return html.includes("<pre")
|
||||
? html.trim()
|
||||
: html
|
||||
.split(/\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.length)
|
||||
.join(" ");
|
||||
};
|
||||
// /**
|
||||
// * a tagged template processor for raw html:
|
||||
// * stringifies, minifies, and syntax highlights
|
||||
// * @example web.raw`<p>hello</p>`
|
||||
// * @returns {string} the processed html
|
||||
// */
|
||||
// export const raw = (str, ...templates) => {
|
||||
// const html = str
|
||||
// .map(
|
||||
// (chunk) =>
|
||||
// chunk +
|
||||
// (["string", "number"].includes(typeof templates[0])
|
||||
// ? templates.shift()
|
||||
// : escape(JSON.stringify(templates.shift(), null, 2) ?? ""))
|
||||
// )
|
||||
// .join("");
|
||||
// return html.includes("<pre")
|
||||
// ? html.trim()
|
||||
// : html
|
||||
// .split(/\n/)
|
||||
// .map((line) => line.trim())
|
||||
// .filter((line) => line.length)
|
||||
// .join(" ");
|
||||
// };
|
||||
|
||||
/**
|
||||
* create a single html element inc. attributes and children from a string
|
||||
* @example web.html`<p>hello</p>`
|
||||
* @returns {Element} the constructed html element
|
||||
*/
|
||||
export const html = (str, ...templates) => {
|
||||
const $fragment = document.createRange().createContextualFragment(raw(str, ...templates));
|
||||
return $fragment.children.length === 1 ? $fragment.children[0] : $fragment.children;
|
||||
};
|
||||
// /**
|
||||
// * create a single html element inc. attributes and children from a string
|
||||
// * @example web.html`<p>hello</p>`
|
||||
// * @returns {Element} the constructed html element
|
||||
// */
|
||||
// export const html = (str, ...templates) => {
|
||||
// const $fragment = document.createRange().createContextualFragment(raw(str, ...templates));
|
||||
// return $fragment.children.length === 1 ? $fragment.children[0] : $fragment.children;
|
||||
// };
|
||||
|
||||
/**
|
||||
* appends a list of html elements to a parent
|
||||
* @param $container - the parent element
|
||||
* @param $elems - the elements to be appended
|
||||
* @returns {Element} the updated $container
|
||||
*/
|
||||
export const render = ($container, ...$elems) => {
|
||||
$elems = $elems
|
||||
.map(($elem) => ($elem instanceof HTMLCollection ? [...$elem] : $elem))
|
||||
.flat(Infinity)
|
||||
.filter(($elem) => $elem);
|
||||
$container.append(...$elems);
|
||||
return $container;
|
||||
};
|
||||
// /**
|
||||
// * appends a list of html elements to a parent
|
||||
// * @param $container - the parent element
|
||||
// * @param $elems - the elements to be appended
|
||||
// * @returns {Element} the updated $container
|
||||
// */
|
||||
// export const render = ($container, ...$elems) => {
|
||||
// $elems = $elems
|
||||
// .map(($elem) => ($elem instanceof HTMLCollection ? [...$elem] : $elem))
|
||||
// .flat(Infinity)
|
||||
// .filter(($elem) => $elem);
|
||||
// $container.append(...$elems);
|
||||
// return $container;
|
||||
// };
|
||||
|
||||
/**
|
||||
* removes all children from an element without deleting them/their behaviours
|
||||
* @param $container - the parent element
|
||||
* @returns {Element} the updated $container
|
||||
*/
|
||||
export const empty = ($container) => {
|
||||
while ($container.firstChild && $container.removeChild($container.firstChild));
|
||||
return $container;
|
||||
};
|
||||
// /**
|
||||
// * removes all children from an element without deleting them/their behaviours
|
||||
// * @param $container - the parent element
|
||||
// * @returns {Element} the updated $container
|
||||
// */
|
||||
// export const empty = ($container) => {
|
||||
// while ($container.firstChild && $container.removeChild($container.firstChild));
|
||||
// return $container;
|
||||
// };
|
||||
|
||||
/**
|
||||
* loads/applies a css stylesheet to the page
|
||||
* @param {string} path - a url or within-the-enhancer filepath
|
||||
*/
|
||||
export const loadStylesheet = (path) => {
|
||||
const $stylesheet = html`<link
|
||||
rel="stylesheet"
|
||||
href="${path.startsWith("https://") ? path : fs.localPath(path)}"
|
||||
/>`;
|
||||
render(document.head, $stylesheet);
|
||||
return $stylesheet;
|
||||
};
|
||||
// /**
|
||||
// * loads/applies a css stylesheet to the page
|
||||
// * @param {string} path - a url or within-the-enhancer filepath
|
||||
// */
|
||||
// export const loadStylesheet = (path) => {
|
||||
// const $stylesheet = html`<link
|
||||
// rel="stylesheet"
|
||||
// href="${path.startsWith("https://") ? path : fs.localPath(path)}"
|
||||
// />`;
|
||||
// render(document.head, $stylesheet);
|
||||
// return $stylesheet;
|
||||
// };
|
||||
|
||||
/**
|
||||
* copy text to the clipboard
|
||||
* @param {string} str - the string to copy
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const copyToClipboard = async (str) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(str);
|
||||
} catch {
|
||||
const $el = document.createElement("textarea");
|
||||
$el.value = str;
|
||||
$el.setAttribute("readonly", "");
|
||||
$el.style.position = "absolute";
|
||||
$el.style.left = "-9999px";
|
||||
document.body.appendChild($el);
|
||||
$el.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild($el);
|
||||
}
|
||||
};
|
||||
// /**
|
||||
// * copy text to the clipboard
|
||||
// * @param {string} str - the string to copy
|
||||
// * @returns {Promise<void>}
|
||||
// */
|
||||
// export const copyToClipboard = async (str) => {
|
||||
// try {
|
||||
// await navigator.clipboard.writeText(str);
|
||||
// } catch {
|
||||
// const $el = document.createElement("textarea");
|
||||
// $el.value = str;
|
||||
// $el.setAttribute("readonly", "");
|
||||
// $el.style.position = "absolute";
|
||||
// $el.style.left = "-9999px";
|
||||
// document.body.appendChild($el);
|
||||
// $el.select();
|
||||
// document.execCommand("copy");
|
||||
// document.body.removeChild($el);
|
||||
// }
|
||||
// };
|
||||
|
||||
/**
|
||||
* read text from the clipboard
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export const readFromClipboard = () => {
|
||||
return navigator.clipboard.readText();
|
||||
};
|
||||
// /**
|
||||
// * read text from the clipboard
|
||||
// * @returns {Promise<string>}
|
||||
// */
|
||||
// export const readFromClipboard = () => {
|
||||
// return navigator.clipboard.readText();
|
||||
// };
|
||||
|
||||
const triggerHotkeyListener = (event, hotkey) => {
|
||||
const inInput = document.activeElement.nodeName === "INPUT" && !hotkey.listenInInput;
|
||||
if (inInput) return;
|
||||
const modifiers = {
|
||||
metaKey: ["meta", "os", "win", "cmd", "command"],
|
||||
ctrlKey: ["ctrl", "control"],
|
||||
shiftKey: ["shift"],
|
||||
altKey: ["alt"],
|
||||
},
|
||||
pressed = hotkey.keys.every((key) => {
|
||||
key = key.toLowerCase();
|
||||
for (const modifier in modifiers) {
|
||||
const pressed = modifiers[modifier].includes(key) && event[modifier];
|
||||
if (pressed) {
|
||||
// mark modifier as part of hotkey
|
||||
modifiers[modifier] = [];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (key === "space") key = " ";
|
||||
if (key === "plus") key = "+";
|
||||
if (key === event.key.toLowerCase()) return true;
|
||||
});
|
||||
if (!pressed) return;
|
||||
// test for modifiers not in hotkey
|
||||
// e.g. to differentiate ctrl+x from ctrl+shift+x
|
||||
for (const modifier in modifiers) {
|
||||
const modifierPressed = event[modifier],
|
||||
modifierNotInHotkey = modifiers[modifier].length > 0;
|
||||
if (modifierPressed && modifierNotInHotkey) return;
|
||||
}
|
||||
hotkey.callback(event);
|
||||
};
|
||||
// const triggerHotkeyListener = (event, hotkey) => {
|
||||
// const inInput = document.activeElement.nodeName === "INPUT" && !hotkey.listenInInput;
|
||||
// if (inInput) return;
|
||||
// const modifiers = {
|
||||
// metaKey: ["meta", "os", "win", "cmd", "command"],
|
||||
// ctrlKey: ["ctrl", "control"],
|
||||
// shiftKey: ["shift"],
|
||||
// altKey: ["alt"],
|
||||
// },
|
||||
// pressed = hotkey.keys.every((key) => {
|
||||
// key = key.toLowerCase();
|
||||
// for (const modifier in modifiers) {
|
||||
// const pressed = modifiers[modifier].includes(key) && event[modifier];
|
||||
// if (pressed) {
|
||||
// // mark modifier as part of hotkey
|
||||
// modifiers[modifier] = [];
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// if (key === "space") key = " ";
|
||||
// if (key === "plus") key = "+";
|
||||
// if (key === event.key.toLowerCase()) return true;
|
||||
// });
|
||||
// if (!pressed) return;
|
||||
// // test for modifiers not in hotkey
|
||||
// // e.g. to differentiate ctrl+x from ctrl+shift+x
|
||||
// for (const modifier in modifiers) {
|
||||
// const modifierPressed = event[modifier],
|
||||
// modifierNotInHotkey = modifiers[modifier].length > 0;
|
||||
// if (modifierPressed && modifierNotInHotkey) return;
|
||||
// }
|
||||
// hotkey.callback(event);
|
||||
// };
|
||||
|
||||
/**
|
||||
* register a hotkey listener to the page
|
||||
* @param {array|string} keys - the combination of keys that will trigger the hotkey.
|
||||
* key codes can be tested at http://keycode.info/ and are case-insensitive.
|
||||
* available modifiers are 'alt', 'ctrl', 'meta', and 'shift'.
|
||||
* can be provided as a + separated string.
|
||||
* @param {function} callback - called whenever the keys are pressed
|
||||
* @param {object=} opts - fine-tuned control over when the hotkey should be triggered
|
||||
* @param {boolean=} opts.listenInInput - whether the hotkey callback should be triggered
|
||||
* when an input is focused
|
||||
* @param {boolean=} opts.keydown - whether to listen for the hotkey on keydown.
|
||||
* by default, hotkeys are triggered by the keyup event.
|
||||
*/
|
||||
export const addHotkeyListener = (
|
||||
keys,
|
||||
callback,
|
||||
{ listenInInput = false, keydown = false } = {}
|
||||
) => {
|
||||
if (typeof keys === "string") keys = keys.split("+");
|
||||
_hotkeyEventListeners.push({ keys, callback, listenInInput, keydown });
|
||||
// /**
|
||||
// * register a hotkey listener to the page
|
||||
// * @param {array|string} keys - the combination of keys that will trigger the hotkey.
|
||||
// * key codes can be tested at http://keycode.info/ and are case-insensitive.
|
||||
// * available modifiers are 'alt', 'ctrl', 'meta', and 'shift'.
|
||||
// * can be provided as a + separated string.
|
||||
// * @param {function} callback - called whenever the keys are pressed
|
||||
// * @param {object=} opts - fine-tuned control over when the hotkey should be triggered
|
||||
// * @param {boolean=} opts.listenInInput - whether the hotkey callback should be triggered
|
||||
// * when an input is focused
|
||||
// * @param {boolean=} opts.keydown - whether to listen for the hotkey on keydown.
|
||||
// * by default, hotkeys are triggered by the keyup event.
|
||||
// */
|
||||
// export const addHotkeyListener = (
|
||||
// keys,
|
||||
// callback,
|
||||
// { listenInInput = false, keydown = false } = {}
|
||||
// ) => {
|
||||
// if (typeof keys === "string") keys = keys.split("+");
|
||||
// _hotkeyEventListeners.push({ keys, callback, listenInInput, keydown });
|
||||
|
||||
if (!_hotkeyListenersActivated) {
|
||||
_hotkeyListenersActivated = true;
|
||||
document.addEventListener("keyup", (event) => {
|
||||
for (const hotkey of _hotkeyEventListeners.filter(({ keydown }) => !keydown)) {
|
||||
triggerHotkeyListener(event, hotkey);
|
||||
}
|
||||
});
|
||||
document.addEventListener("keydown", (event) => {
|
||||
for (const hotkey of _hotkeyEventListeners.filter(({ keydown }) => keydown)) {
|
||||
triggerHotkeyListener(event, hotkey);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* remove a listener added with web.addHotkeyListener
|
||||
* @param {function} callback
|
||||
*/
|
||||
export const removeHotkeyListener = (callback) => {
|
||||
_hotkeyEventListeners = _hotkeyEventListeners.filter(
|
||||
(listener) => listener.callback !== callback
|
||||
);
|
||||
};
|
||||
// if (!_hotkeyListenersActivated) {
|
||||
// _hotkeyListenersActivated = true;
|
||||
// document.addEventListener("keyup", (event) => {
|
||||
// for (const hotkey of _hotkeyEventListeners.filter(({ keydown }) => !keydown)) {
|
||||
// triggerHotkeyListener(event, hotkey);
|
||||
// }
|
||||
// });
|
||||
// document.addEventListener("keydown", (event) => {
|
||||
// for (const hotkey of _hotkeyEventListeners.filter(({ keydown }) => keydown)) {
|
||||
// triggerHotkeyListener(event, hotkey);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
// /**
|
||||
// * remove a listener added with web.addHotkeyListener
|
||||
// * @param {function} callback
|
||||
// */
|
||||
// export const removeHotkeyListener = (callback) => {
|
||||
// _hotkeyEventListeners = _hotkeyEventListeners.filter(
|
||||
// (listener) => listener.callback !== callback
|
||||
// );
|
||||
// };
|
||||
|
||||
/**
|
||||
* add a listener to watch for changes to the dom
|
||||
* @param {onDocumentObservedCallback} callback
|
||||
* @param {string[]=} selectors
|
||||
*/
|
||||
export const addDocumentObserver = (callback, selectors = []) => {
|
||||
if (!_documentObserver) {
|
||||
const handle = (queue) => {
|
||||
while (queue.length) {
|
||||
const event = queue.shift(),
|
||||
matchesAddedNode = ($node, selector) =>
|
||||
$node instanceof Element &&
|
||||
($node.matches(selector) ||
|
||||
$node.matches(`${selector} *`) ||
|
||||
$node.querySelector(selector)),
|
||||
matchesTarget = (selector) =>
|
||||
event.target.matches(selector) ||
|
||||
event.target.matches(`${selector} *`) ||
|
||||
[...event.addedNodes].some(($node) => matchesAddedNode($node, selector));
|
||||
for (const listener of _documentObserverListeners) {
|
||||
if (!listener.selectors.length || listener.selectors.some(matchesTarget)) {
|
||||
listener.callback(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
_documentObserver = new MutationObserver((list, _observer) => {
|
||||
if (!_documentObserverEvents.length)
|
||||
requestIdleCallback(() => handle(_documentObserverEvents));
|
||||
_documentObserverEvents.push(...list);
|
||||
});
|
||||
_documentObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
});
|
||||
}
|
||||
_documentObserverListeners.push({ callback, selectors });
|
||||
};
|
||||
// /**
|
||||
// * add a listener to watch for changes to the dom
|
||||
// * @param {onDocumentObservedCallback} callback
|
||||
// * @param {string[]=} selectors
|
||||
// */
|
||||
// export const addDocumentObserver = (callback, selectors = []) => {
|
||||
// if (!_documentObserver) {
|
||||
// const handle = (queue) => {
|
||||
// while (queue.length) {
|
||||
// const event = queue.shift(),
|
||||
// matchesAddedNode = ($node, selector) =>
|
||||
// $node instanceof Element &&
|
||||
// ($node.matches(selector) ||
|
||||
// $node.matches(`${selector} *`) ||
|
||||
// $node.querySelector(selector)),
|
||||
// matchesTarget = (selector) =>
|
||||
// event.target.matches(selector) ||
|
||||
// event.target.matches(`${selector} *`) ||
|
||||
// [...event.addedNodes].some(($node) => matchesAddedNode($node, selector));
|
||||
// for (const listener of _documentObserverListeners) {
|
||||
// if (!listener.selectors.length || listener.selectors.some(matchesTarget)) {
|
||||
// listener.callback(event);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// _documentObserver = new MutationObserver((list, _observer) => {
|
||||
// if (!_documentObserverEvents.length)
|
||||
// requestIdleCallback(() => handle(_documentObserverEvents));
|
||||
// _documentObserverEvents.push(...list);
|
||||
// });
|
||||
// _documentObserver.observe(document.body, {
|
||||
// childList: true,
|
||||
// subtree: true,
|
||||
// attributes: true,
|
||||
// });
|
||||
// }
|
||||
// _documentObserverListeners.push({ callback, selectors });
|
||||
// };
|
||||
|
||||
/**
|
||||
* remove a listener added with web.addDocumentObserver
|
||||
* @param {onDocumentObservedCallback} callback
|
||||
*/
|
||||
export const removeDocumentObserver = (callback) => {
|
||||
_documentObserverListeners = _documentObserverListeners.filter(
|
||||
(listener) => listener.callback !== callback
|
||||
);
|
||||
};
|
||||
// /**
|
||||
// * remove a listener added with web.addDocumentObserver
|
||||
// * @param {onDocumentObservedCallback} callback
|
||||
// */
|
||||
// export const removeDocumentObserver = (callback) => {
|
||||
// _documentObserverListeners = _documentObserverListeners.filter(
|
||||
// (listener) => listener.callback !== callback
|
||||
// );
|
||||
// };
|
||||
|
||||
/**
|
||||
* @callback onDocumentObservedCallback
|
||||
* @param {MutationRecord} event - the observed dom mutation event
|
||||
*/
|
||||
// /**
|
||||
// * @callback onDocumentObservedCallback
|
||||
// * @param {MutationRecord} event - the observed dom mutation event
|
||||
// */
|
||||
|
29
src/core/client.js
Normal file
29
src/core/client.js
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* notion-enhancer
|
||||
* (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||
* (https://notion-enhancer.github.io/) under the MIT license
|
||||
*/
|
||||
|
||||
import "../vendor/twind.min.js";
|
||||
import * as lucide from "../vendor/lucide.min.js";
|
||||
import { html } from "../vendor/htm+preact.min.js";
|
||||
|
||||
export default async () => {
|
||||
// const sidebarSelector =
|
||||
// ".notion-sidebar-container .notion-sidebar > div:nth-child(3) > div > div:nth-child(2)";
|
||||
// await web.whenReady([sidebarSelector]);
|
||||
|
||||
console.log(lucide);
|
||||
|
||||
const $sidebarLink = html`<div
|
||||
class="enhancer--sidebarMenuLink"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div>
|
||||
<div><div>notion-enhancer</div></div>
|
||||
</div>
|
||||
</div>`;
|
||||
// <div>${await fs.getText("media/colour.svg")}</div>
|
||||
// $sidebarLink.addEventListener("click", env.focusMenu);
|
||||
};
|
12
src/core/menu.html
Normal file
12
src/core/menu.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>notion-enhancer menu</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>hello world</p>
|
||||
</body>
|
||||
</html>
|
@ -36,9 +36,19 @@
|
||||
"type": "file",
|
||||
"key": "customStyles",
|
||||
"description": "Adds the styles from an uploaded .css file to Notion. Use this if you would like to customise the current theme or <a href=\"https://notion-enhancer.github.io/advanced/tweaks\">otherwise tweak Notion's appearance</a>."
|
||||
},
|
||||
{
|
||||
"type": "heading",
|
||||
"label": "Advanced"
|
||||
},
|
||||
{
|
||||
"type": "toggle",
|
||||
"key": "debugMode",
|
||||
"description": "Activates built-in debugging tools accessible through the application menu.",
|
||||
"value": false
|
||||
}
|
||||
],
|
||||
"clientStyles": [],
|
||||
"clientScripts": [],
|
||||
"clientScripts": ["client.js"],
|
||||
"electronScripts": []
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ const initDatabase = (namespace) => {
|
||||
dump = db.prepare(`SELECT * FROM ${table}`),
|
||||
populate = db.transaction((obj) => {
|
||||
for (const key in obj) {
|
||||
if (select.get(key)) update.run(value, key);
|
||||
else insert.run(key, value);
|
||||
if (select.get(key)) update.run(obj[key], key);
|
||||
else insert.run(key, obj[key]);
|
||||
}
|
||||
});
|
||||
|
||||
|
1
src/vendor/htm+preact.min.js
vendored
Normal file
1
src/vendor/htm+preact.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user