mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-12 00:09:03 +00:00
100 lines
3.2 KiB
JavaScript
100 lines
3.2 KiB
JavaScript
/**
|
|
* 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 "../vendor/lucide.min.js";
|
|
import htm from "../vendor/htm.min.js";
|
|
|
|
const { readFile } = globalThis.__enhancerApi,
|
|
enhancerIconColour = await readFile("/assets/colour.svg"),
|
|
enhancerIconMonochrome = await readFile("/assets/monochrome.svg");
|
|
|
|
const kebabToPascalCase = (string) =>
|
|
string[0].toUpperCase() +
|
|
string.replace(/-[a-z]/g, (match) => match.slice(1).toUpperCase()).slice(1),
|
|
hToString = (type, props, ...children) =>
|
|
`<${type}${Object.entries(props)
|
|
.map(([attr, value]) => ` ${attr}="${value}"`)
|
|
.join("")}>${children
|
|
.flat(Infinity)
|
|
.map(([tag, attrs, children]) => hToString(tag, attrs, children))
|
|
.join("")}</${type}>`;
|
|
|
|
// https://gist.github.com/jennyknuth/222825e315d45a738ed9d6e04c7a88d0
|
|
const encodeSvg = (svg) =>
|
|
svg
|
|
.replace(
|
|
"<svg",
|
|
~svg.indexOf("xmlns") ? "<svg" : '<svg xmlns="http://www.w3.org/2000/svg"'
|
|
)
|
|
.replace(/"/g, "'")
|
|
.replace(/%/g, "%25")
|
|
.replace(/#/g, "%23")
|
|
.replace(/{/g, "%7B")
|
|
.replace(/}/g, "%7D")
|
|
.replace(/</g, "%3C")
|
|
.replace(/>/g, "%3E")
|
|
.replace(/\s+/g, " ");
|
|
|
|
// https://antfu.me/posts/icons-in-pure-css
|
|
const presetIcons = () => ({
|
|
rules: [
|
|
[
|
|
/^i-((?:\w|-)+)(?:\?(mask|bg|auto))?$/,
|
|
([, icon, mode]) => {
|
|
let svg;
|
|
// manually register i-notion-enhancer: renders the colour
|
|
// version by default, renders the monochrome version when
|
|
// mask mode is requested via i-notion-enhancer?mask
|
|
if (icon === "notion-enhancer") {
|
|
svg = mode === "mask" ? enhancerIconMonochrome : enhancerIconColour;
|
|
} else {
|
|
icon = kebabToPascalCase(icon);
|
|
if (!globalThis.lucide[icon]) return;
|
|
svg = hToString(...globalThis.lucide[icon]);
|
|
}
|
|
const dataUri = `url("data:image/svg+xml;utf8,${encodeSvg(svg)}")`;
|
|
if (mode === "auto") mode = undefined;
|
|
mode ??= svg.includes("currentColor") ? "mask" : "bg";
|
|
return mode === "mask"
|
|
? {
|
|
mask: `${dataUri} no-repeat`,
|
|
"mask-size": "100% 100%",
|
|
"background-color": "currentColor",
|
|
color: "inherit",
|
|
height: "1em",
|
|
width: "1em",
|
|
}
|
|
: {
|
|
background: `${dataUri} no-repeat`,
|
|
"background-size": "100% 100%",
|
|
"background-color": "transparent",
|
|
height: "1em",
|
|
width: "1em",
|
|
};
|
|
},
|
|
],
|
|
],
|
|
});
|
|
|
|
const { twind } = globalThis;
|
|
twind.install({ presets: [presetIcons()] });
|
|
|
|
// constructs elements via html`tagged templates`
|
|
const h = (type, props, ...children) => {
|
|
const elem = document.createElement(type);
|
|
for (const prop in props) {
|
|
if (["string", "number", "boolean"].includes(typeof props[prop])) {
|
|
elem.setAttribute(prop, props[prop]);
|
|
} else elem[prop] = props[prop];
|
|
}
|
|
for (const child of children) elem.append(child);
|
|
return elem;
|
|
},
|
|
html = htm.bind(h);
|
|
|
|
export { html, twind };
|