/** * notion-enhancer * (c) 2023 dragonwocky (https://dragonwocky.me/) * (https://notion-enhancer.github.io/) under the MIT license */ "use strict"; const { twind, htm } = globalThis, { readFile } = globalThis.__enhancerApi; let iconColour, iconMonochrome; (async () => { iconColour = await readFile("/assets/colour.svg"); iconMonochrome = 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 .map((child) => (Array.isArray(child) ? hToString(...child) : child)) .join("")}`; const encodeSvg = (svg) => // https://gist.github.com/jennyknuth/222825e315d45a738ed9d6e04c7a88d0 svg .replace( "/g, "%3E") .replace(/\s+/g, " "), presetIcons = ([, 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" ? iconMonochrome : iconColour; } else { icon = kebabToPascalCase(icon); if (!globalThis.lucide[icon]) return; const [type, props, children] = globalThis.lucide[icon]; svg = hToString(type, props, ...children); } // https://antfu.me/posts/icons-in-pure-css const dataUri = `url("data:image/svg+xml;utf8,${encodeSvg(svg)}")`; if (mode === "auto") mode = undefined; mode ??= svg.includes("currentColor") ? "mask" : "bg"; return { display: "inline-block", height: "1em", width: "1em", ...(mode === "mask" ? { mask: `${dataUri} no-repeat`, "mask-size": "100% 100%", "background-color": "currentColor", color: "inherit", } : { background: `${dataUri} no-repeat`, "background-size": "100% 100%", "background-color": "transparent", }), }; }; twind.install({ rules: [[/^i-((?:\w|-)+)(?:\?(mask|bg|auto))?$/, presetIcons]], variants: [ // https://github.com/tw-in-js/twind/blob/main/packages/preset-ext/src/variants.ts [ "not-([a-z-]+|\\[.+\\])", ({ 1: $1 }) => `&:not(${($1[0] == "[" ? "" : ":") + $1})`, ], ["children", "&>*"], ["siblings", "&~*"], ["sibling", "&+*"], ["override", "&&"], ["\\[.+]", (match) => "&" + match.input], ["([a-z-]+):", ({ 1: $1 }) => "&::" + $1], ], }); // https://developer.mozilla.org/en-US/docs/Web/SVG/Element const svgElements = [ "animate", "animateMotion", "animateTransform", "circle", "clipPath", "defs", "desc", "discard", "ellipse", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "filter", "foreignObject", "g", "hatch", "hatchpath", "image", "line", "linearGradient", "marker", "mask", "metadata", "mpath", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "script", "set", "stop", "style", "svg", "switch", "symbol", "text", "textPath", "title", "tspan", "use", "view", ], htmlAttributes = [ // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes "accept", "accept-charset", "accesskey", "action", "align", "allow", "alt", "async", "autocapitalize", "autocomplete", "autofocus", "autoplay", "background", "bgcolor", "border", "buffered", "capture", "challenge", "charset", "checked", "cite", "class", "code", "codebase", "color", "cols", "colspan", "content", "contenteditable", "contextmenu", "controls", "coords", "crossorigin", "csp", "data", "data-*", "datetime", "decoding", "default", "defer", "dir", "dirname", "disabled", "download", "draggable", "enctype", "enterkeyhint", "for", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "headers", "height", "hidden", "high", "href", "hreflang", "http-equiv", "icon", "id", "importance", "integrity", "inputmode", "ismap", "itemprop", "keytype", "kind", "label", "lang", "loading", "list", "loop", "low", "max", "maxlength", "minlength", "media", "method", "min", "multiple", "muted", "name", "novalidate", "open", "optimum", "pattern", "ping", "placeholder", "playsinline", "poster", "preload", "radiogroup", "readonly", "referrerpolicy", "rel", "required", "reversed", "role", "rows", "rowspan", "sandbox", "scope", "selected", "shape", "size", "sizes", "slot", "span", "spellcheck", "src", "srcdoc", "srclang", "srcset", "start", "step", "style", "tabindex", "target", "title", "translate", "type", "usemap", "value", "width", "wrap", // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute[ "accent-height", "accumulate", "additive", "alignment-baseline", "alphabetic", "amplitude", "arabic-form", "ascent", "attributeName", "attributeType", "azimuth", "baseFrequency", "baseline-shift", "baseProfile", "bbox", "begin", "bias", "by", "calcMode", "cap-height", "clip", "clipPathUnits", "clip-path", "clip-rule", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "contentScriptType", "contentStyleType", "cursor", "cx", "cy", "d", "decelerate", "descent", "diffuseConstant", "direction", "display", "divisor", "dominant-baseline", "dur", "dx", "dy", "edgeMode", "elevation", "enable-background", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterRes", "filterUnits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "format", "from", "fr", "fx", "fy", "g1", "g2", "glyph-name", "glyph-orientation-horizontal", "glyph-orientation-vertical", "glyphRef", "gradientTransform", "gradientUnits", "hanging", "horiz-adv-x", "horiz-origin-x", "ideographic", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kernelMatrix", "kernelUnitLength", "kerning", "keyPoints", "keySplines", "keyTimes", "lengthAdjust", "letter-spacing", "lighting-color", "limitingConeAngle", "local", "marker-end", "marker-mid", "marker-start", "markerHeight", "markerUnits", "markerWidth", "mask", "maskContentUnits", "maskUnits", "mathematical", "mode", "numOctaves", "offset", "opacity", "operator", "order", "orient", "orientation", "origin", "overflow", "overline-position", "overline-thickness", "panose-1", "paint-order", "path", "pathLength", "patternContentUnits", "patternTransform", "patternUnits", "pointer-events", "points", "pointsAtX", "pointsAtY", "pointsAtZ", "preserveAlpha", "preserveAspectRatio", "primitiveUnits", "r", "radius", "referrerPolicy", "refX", "refY", "rendering-intent", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "restart", "result", "rotate", "rx", "ry", "scale", "seed", "shape-rendering", "slope", "spacing", "specularConstant", "specularExponent", "speed", "spreadMethod", "startOffset", "stdDeviation", "stemh", "stemv", "stitchTiles", "stop-color", "stop-opacity", "strikethrough-position", "strikethrough-thickness", "string", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "surfaceScale", "systemLanguage", "tableValues", "targetX", "targetY", "text-anchor", "text-decoration", "text-rendering", "textLength", "to", "transform", "transform-origin", "u1", "u2", "underline-position", "underline-thickness", "unicode", "unicode-bidi", "unicode-range", "units-per-em", "v-alphabetic", "v-hanging", "v-ideographic", "v-mathematical", "values", "vector-effect", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "viewBox", "viewTarget", "visibility", "widths", "word-spacing", "writing-mode", "x", "x-height", "x1", "x2", "xChannelSelector", "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "y", "y1", "y2", "yChannelSelector", "z", "zoomAndPan", ]; // html`
` const h = (type, props, ...children) => { children = children.flat(Infinity); // html`<${Component} attr="value">Click Me` if (typeof type === "function") { return type(props ?? {}, ...children); } const elem = svgElements.includes(type) ? document.createElementNS("http://www.w3.org/2000/svg", type) : document.createElement(type); for (const prop in props ?? {}) { if (htmlAttributes.includes(prop)) { elem.setAttribute(prop, props[prop]); } else elem[prop] = props[prop]; } elem.append(...children); return elem; }, html = htm.bind(h); globalThis.__enhancerApi ??= {}; Object.assign(globalThis.__enhancerApi, { html });