/** * notion-enhancer * (c) 2023 dragonwocky (https://dragonwocky.me/) * (https://notion-enhancer.github.io/) under the MIT license */ // paste this in the devtools console at to generate theme css // at https://www.notion.so/9390e51f458940a5a339dc4b8fdea2fb. // to detect fonts, open the ... menu before running. // repeat for both light and dark modes, pass the css through // https://css-minifier.com/ and https://css.github.io/csso/csso.html // and then save it to core/variables.css and core/theme.css // todo: svg page & property icons const darkMode = document.body.classList.contains("dark"), modeSelector = darkMode ? ".dark" : ":not(.dark)", bodySelector = `.notion-body${modeSelector}`; let cssRoot = "", cssBody = "", cssRefs = {}; const getComputedPropertyValue = (el, prop) => { const styles = window.getComputedStyle(el), value = styles.getPropertyValue(prop); return value; }, cssVariable = ({ name, value, alias, splitValues = false }) => { const values = splitValues ? value.split(", ") : [value], rgbPattern = /^rgba?\(\d{1,3},\d{1,3},\d{1,3}(?:,\d{1,3})?\)$/, isColor = rgbPattern.test(value.replace(/\s/g, "")); if (isColor) { values[0] = values[0].replace(/\s/g, ""); const hasOpaqueAlpha = values[0].trim().startsWith("rgba(") && values[0].trim().endsWith(",1)"); if (hasOpaqueAlpha) values[0] = `rgb(${values[0].slice(5, -3)})`; } if (!cssRoot.includes(`--theme--${name}:`)) { cssRoot += `--theme--${name}:${ alias ? `var(--theme--${alias})` : value };`; } return { name, value, ref: `var(--theme--${name},${values[0]})${ values.length > 1 ? ", " : "" }${values.slice(1).join(", ")} !important`, }; }, overrideStyle = ({ element, selector = "", property, variable, variableAliases = {}, valueAliases = [], specificity = ["mode", "value"], cssProps = {}, postProcessor = (selector, cssProps) => [selector, cssProps], }) => { if (selector) element ??= document.querySelector(selector); const style = element?.getAttribute("style") ?? "", pattern = String.raw`(?:^|(?:;\s*))${property}:\s*([^;]+);?`, match = style.match(new RegExp(pattern)); if (typeof variable === "string") { let value = match?.[1]; if (element) { value ??= getComputedPropertyValue( element, property === "background" ? "background-color" : property ); } if (!value) throw new Error(`${property} not found for ${selector}`); variable = cssVariable({ name: variable, value: value, alias: variableAliases[value], splitValues: property === "font-family", }); } if (specificity.includes("value")) { if (/(? property === "color" ? `[style^="color: ${value}"], [style^="color:${value}"], [style*=";color: ${value}"], [style*=";color:${value}"], [style*=" color: ${value}"], [style*=" color:${value}"], [style*="fill: ${value}"], [style*="fill:${value}"]` : property === "background" ? `[style^="background: ${value}"], [style^="background:${value}"], [style*=";background: ${value}"], [style*=";background:${value}"], [style*=" background: ${value}"], [style*=" background:${value}"], [style*="background-color: ${value}"], [style*="background-color:${value}"]` : `[style*="${property}: ${value}"], [style*="${property}:${value}"]` ) .join(","); selector += selector ? `:is(${propSelector})` : propSelector; } } if (specificity.includes("mode")) { selector = /(? prop && val) .map(([prop, val]) => `${prop}:${val?.ref ?? val}`) .join(";"); cssRefs[body] ??= []; cssRefs[body].push(selector); variableAliases[variable.value] ??= variable.name; }; const styleText = () => { const primary = cssVariable({ name: "fg-primary", value: darkMode ? "rgba(255, 255, 255, 0.81)" : "rgb(55, 53, 47)", }), primaryAliases = darkMode ? [ "rgb(211, 211, 211)", "rgb(255, 255, 255)", "rgba(255, 255, 255, 0.8", "rgba(255, 255, 255, 0.9", "rgba(255, 255, 255, 1", ] : [ "rgba(255, 255, 255, 0.9)", "rgba(55, 53, 47, 0.8", "rgba(55, 53, 47, 0.9", "rgba(55, 53, 47, 1", ]; const secondary = cssVariable({ name: "fg-secondary", value: darkMode ? "rgb(155, 155, 155)" : "rgba(25, 23, 17, 0.6)", }), secondaryAliases = darkMode ? [ "rgb(127, 127, 127)", "rgba(255, 255, 255, 0.0", "rgba(255, 255, 255, 0.1", "rgba(255, 255, 255, 0.2", "rgba(255, 255, 255, 0.3", "rgba(255, 255, 255, 0.4", "rgba(255, 255, 255, 0.5", "rgba(255, 255, 255, 0.6", "rgba(255, 255, 255, 0.7", ] : [ "rgba(206, 205, 202, 0.6)", "rgba(55, 53, 47, 0.0", "rgba(55, 53, 47, 0.1", "rgba(55, 53, 47, 0.2", "rgba(55, 53, 47, 0.3", "rgba(55, 53, 47, 0.4", "rgba(55, 53, 47, 0.5", "rgba(55, 53, 47, 0.6", "rgba(55, 53, 47, 0.7", ]; overrideStyle({ property: "color", variable: primary, valueAliases: primaryAliases, cssProps: { "caret-color": primary, "text-decoration-color": "currentColor", fill: primary, }, }); overrideStyle({ property: "color", variable: secondary, valueAliases: secondaryAliases, cssProps: { "caret-color": secondary, "text-decoration-color": "currentColor", fill: secondary, }, postProcessor(selector, cssProps) { return [ `${bodySelector} :is(.rdp-nav_icon, .rdp-head_cell, .rdp-day.rdp-day_outside, ::placeholder), ${selector}`, cssProps, ]; }, }); overrideStyle({ property: "caret-color", variable: primary, valueAliases: primaryAliases, }); overrideStyle({ property: "caret-color", variable: secondary, valueAliases: secondaryAliases, }); overrideStyle({ selector: `[style*="-webkit-text-fill-color:"]`, property: "-webkit-text-fill-color", variable: secondary, specificity: ["mode"], }); // light mode tags have coloured text, // replace with primary text for inter-mode consistency for (const tagSelector of [ `[style*="height: 20px; border-radius: 3px; padding-left: 6px;"][style*="background:"]`, `.notion-collection_view-block [style*="height: 14px; border-radius: 3px; padding-left: 6px;"]`, `.notion-timeline-item-properties [style*="height: 18px; border-radius: 3px; padding-left: 8px;"]`, ]) { for (const el of document.querySelectorAll(tagSelector)) { if (darkMode) continue; overrideStyle({ element: el, selector: tagSelector, property: "color", variable: "fg-primary", }); } } }; const styleBorders = () => { const border = cssVariable({ name: "fg-border", value: darkMode ? "rgb(47, 47, 47)" : "rgb(233, 233, 231)", }), borderColors = darkMode ? [border.value.slice(4, -1), "37, 37, 37", "255, 255, 255"] : [border.value.slice(4, -1), "238, 238, 237", "55, 53, 47"], boxShadows = darkMode ? [ "; box-shadow: rgba(255, 255, 255, 0.094) 0px -1px 0px;", "; box-shadow: rgba(15, 15, 15, 0.2) 0px 0px 0px 1px inset;", "; box-shadow: rgb(25, 25, 25) -3px 0px 0px, rgb(47, 47, 47) 0px 1px 0px;", ] : [ "; box-shadow: rgba(55, 53, 47, 0.09) 0px -1px 0px;", "; box-shadow: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px inset;", "; box-shadow: white -3px 0px 0px, rgb(233, 233, 231) 0px 1px 0px;", ]; for (const el of document.querySelectorAll(`[style*="box-shadow:"]`)) { const boxShadow = el .getAttribute("style") .match(/(?:^|(?:;\s*))box-shadow:\s*([^;]+);?/)?.[0]; if (borderColors.some((color) => boxShadow.includes(color))) { boxShadows.push(boxShadow); } } overrideStyle({ selector: `[style*="height: 1px;"][style*="background"]`, property: "background", variable: border, specificity: ["mode"], }); cssBody += ` ${bodySelector} :is(${[...new Set(borderColors)] .map( (color) => `[style*="px solid rgb(${color}"], [style*="px solid rgba(${color}"]` ) .join(", ")}):is([style*="border:"], [style*="border-top:"], [style*="border-left:"], [style*="border-bottom:"], [style*="border-right:"]) { border-color: ${border.ref}; } ${[...new Set(boxShadows)] .map((shadow) => { if (shadow.startsWith(";")) shadow = shadow.slice(1); return `${bodySelector} [style*="${shadow}"] { ${shadow .replace( /rgba?\([^\)]+\)/g, shadow.includes("-3px 0px 0px, ") ? "transparent" : `var(--theme--fg-border, ${border.value})` ) .slice(0, -1)} !important; }`; }) .join("")} `; }; const styleColoredText = () => { // inline text for (const el of document.querySelectorAll( '.notion-selectable .notion-enable-hover[style*="color:"][style*="fill:"]:not([style*="mono"])' )) { if (!el.innerText || /\s/.test(el.innerText)) continue; overrideStyle({ element: el, selector: ` .notion-selectable .notion-enable-hover, .notion-code-block span.token `, property: "color", variable: `fg-${el.innerText}`, }); } // block text for (const el of document.querySelectorAll( '.notion-text-block > [style*="color:"][style*="fill:"]' )) { if (!el.innerText || /\s/.test(el.innerText)) continue; overrideStyle({ element: el, selector: `.notion-text-block > [style*="color:"][style*="fill:"]`, property: "color", variable: `fg-${el.innerText}`, }); } // board text for (const group of document.querySelectorAll( ".notion-board-view .notion-board-group" )) { // get color name from card const card = group.querySelector('a[style*="background"]'), innerText = card.innerText.replace("Drag image to reposition\n", ""); if (!innerText || /\s/.test(innerText)) continue; const el = group.querySelector('[style*="height: 32px"]'), groupStyle = group .getAttribute("style") .match(/background(?:-color)?:\s*([^;]+);?/)[1]; overrideStyle({ element: el, selector: `.notion-board-view :is( .notion-board-group[style*="${groupStyle}"] [style*="height: 32px"], [style*="${groupStyle}"] > [style*="color"]:nth-child(2), [style*="${groupStyle}"] > div > svg )`, property: "color", // light_gray text doesn't exist variable: `fg-${innerText === "light_gray" ? "secondary" : innerText}`, specificity: ["mode"], }); } }; const styleBackgrounds = () => { const primary = cssVariable({ name: "bg-primary", value: darkMode ? "rgb(25, 25, 25)" : "white", }), secondary = cssVariable({ name: "bg-secondary", value: darkMode ? "rgb(32, 32, 32)" : "rgb(251, 251, 250)", }); overrideStyle({ property: "background", variable: primary, valueAliases: darkMode ? [] : ["rgb(255, 255, 255)", "rgb(247, 247, 247)"], postProcessor(selector, cssProps) { return [`${selector}:not(.notion-timeline-view)`, cssProps]; }, }); overrideStyle({ property: "background", variable: secondary, valueAliases: darkMode ? ["rgb(37, 37, 37)", "rgb(47, 47, 47)"] : ["rgb(253, 253, 253)"], }); // patch: remove overlay from settings sidebar // to match notion-enhancer menu sidebar colour cssBody += `.notion-overlay-container .notion-space-settings > div > div > [style*="height: 100%; background: rgba(255, 255, 255, 0.03);"] { background: transparent !important }`; // cards overrideStyle({ selector: `.notion-timeline-item, .notion-calendar-view .notion-collection-item > a, .notion-gallery-view .notion-collection-item > a`, property: "background", variable: secondary, }); // popups overrideStyle({ selector: `.notion-overlay-container [style*="border-radius: 4px;" ][style*="position: relative; max-width: calc(100vw - 24px); box-shadow:"], [style*="font-size: 12px;"][style*="box-shadow:"][ style*="border-radius: 3px; max-width: calc(100% - 16px); min-height: 24px; overflow: hidden;" ][style*="position: absolute; right: 8px; bottom: 8px; z-index:"], [style*="height: 32px;"][style*="font-size: 14px; line-height: 1.2; border-radius: 5px; box-shadow:"], [style*="transition: background"][style*="cursor: pointer;"][ style*="border-radius: 3px; height: 24px; width: 24px;"][style*="box-shadow:"], [style*="right: 6px; top: 4px;"][style*="border-radius: 4px;"][style*="gap: 1px;"][style*="box-shadow:"]`, property: "background", variable: secondary, }); // modals overrideStyle({ selector: `.notion-overlay-container [data-overlay] :is( [style*="height: 100%; width: 275px;"][style*="flex-direction: column;"], .notion-space-settings [style*="flex-grow: 1"] > [style*="background-color"])`, property: "background", variable: primary, specificity: ["mode"], }); overrideStyle({ selector: `.notion-overlay-container [data-overlay] :is( [style*="height: 100%; width: 275px;"][style*="flex-direction: column;"] + [style*="width: 100%;"], .notion-space-settings [style*="height: 100%; background:"][style*="max-width: 250px;"])`, property: "background", variable: secondary, specificity: ["mode"], }); // timeline fades overrideStyle({ selector: `.notion-timeline-view`, property: "background", variable: primary, specificity: ["mode"], }); cssBody += `[style*="linear-gradient(to left, ${ darkMode ? primary.value : "white" } 20%, rgba(${ darkMode ? primary.value.slice(4, -1) : "255, 255, 255" }, 0) 100%)"] { background-image: linear-gradient(to left, var(--theme--bg-primary, ${primary.value}) 20%, transparent 100%) !important; } [style*="linear-gradient(to right, ${ darkMode ? primary.value : "white" } 20%, rgba(${ darkMode ? primary.value.slice(4, -1) : "255, 255, 255" }, 0) 100%)"] { background-image: linear-gradient(to right, var(--theme--bg-primary, ${primary.value}) 20%, transparent 100%) !important; } `; // hovered elements, inputs and unchecked toggle backgrounds overrideStyle({ property: "background", variable: cssVariable({ name: "bg-hover", value: darkMode ? "rgba(255, 255, 255, 0.055)" : "rgba(55, 53, 47, 0.08)", }), valueAliases: darkMode ? [] : [ "rgba(242, 241, 238, 0.6)", "rgb(225, 225, 225)", "rgb(239, 239, 238)", ], postProcessor(selector, cssProps) { selector += `, ${bodySelector} [style*="height: 14px; width: 26px; border-radius: 44px;"][style*="rgba"]`; if (darkMode) { selector += `, ${bodySelector} :is([style*="background: rgb(47, 47, 47)"], [style*="background-color: rgb(47, 47, 47)"])[style*="transition: background"]:hover`; } return [selector, cssProps]; }, }); // modal shadow overrideStyle({ selector: `.notion-overlay-container [data-overlay] > div > [style*="position: absolute"]:first-child`, property: "background", variable: cssVariable({ name: "bg-overlay", value: darkMode ? "rgba(15, 15, 15, 0.8)" : "rgba(15, 15, 15, 0.6)", }), specificity: ["mode"], }); }; const styleColoredBackgrounds = () => { for (const targetSelector of [ // database tags `[style*="height: 20px; border-radius: 3px; padding-left: 6px;"]`, `.notion-collection_view-block [style*="height: 14px; border-radius: 3px; padding-left: 6px;"]`, `:is(.notion-timeline-item-properties [style*="height: 18px; border-radius: 3px; padding-left: 8px;"], .notion-collection_view-block .notion-collection-item a > .notion-focusable)`, // inline highlights `.notion-selectable .notion-enable-hover[style*="background:"]`, // block highlights and hovered board items `:is(.notion-text-block > [style*="background:"], .notion-collection_view-block .notion-collection-item a > .notion-focusable)`, ]) { for (const el of document.querySelectorAll(targetSelector)) { if (!el.innerText || /\s/.test(el.innerText)) continue; overrideStyle({ element: el, selector: targetSelector, property: "background", variable: `bg-${el.innerText}`, }); } } // board cards for (const group of document.querySelectorAll( ".notion-board-view .notion-board-group" )) { const card = group.querySelector('a[style*="background"]'), innerText = card.innerText.replace("Drag image to reposition\n", ""); if (!innerText || /\s/.test(innerText)) continue; const groupStyle = group .getAttribute("style") .match(/background(?:-color)?:\s*([^;]+);?/)[1]; // in light mode pages in board views all have bg "white" // by default, must be styled based on parent overrideStyle({ element: card, selector: `.notion-board-view .notion-board-group[style*="${groupStyle}"] a`, property: "background", variable: `bg-${innerText}`, specificity: ["mode"], }); overrideStyle({ element: group, selector: `.notion-board-view [style*="${groupStyle}"]:is( .notion-board-group, [style*="border-top-left-radius: 5px;"] )`, property: "background", variable: `dim-${innerText}`, specificity: ["mode"], }); } // use dim for callout blocks for (const el of document.querySelectorAll( '.notion-callout-block > div > [style*="background:"]' )) { if (!el.innerText || /\s/.test(el.innerText)) continue; overrideStyle({ element: el, selector: ".notion-callout-block > div > div", property: "background", variable: `dim-${el.innerText}`, }); } // use yellow for notification highlights overrideStyle({ property: "background", variable: cssVariable({ name: "bg-yellow", value: "rgba(255, 212, 0, 0.14)", }), specificity: ["value"], }); // use light gray for taglikes e.g. file property values overrideStyle({ selector: `[style*="height: 18px; border-radius: 3px; background"]`, property: "background", variable: "bg-light_gray", }); }; const styleTooltips = () => { cssBody += `.notion-overlay-container [style*="border-radius: 3px; background:" ][style*="max-width: calc(100vw - 24px); box-shadow:" ][style*="padding: 4px 8px; font-size: 12px; line-height: 1.4; font-weight: 500;"] { background: rgb(15, 15, 15) !important; color: rgba(255, 255, 255, 0.9) !important; } .notion-overlay-container [style*="border-radius: 3px; background:" ][style*="max-width: calc(100vw - 24px); box-shadow:" ][style*="padding: 4px 8px; font-size: 12px; line-height: 1.4; font-weight: 500;"] > [style*="color"] { color: rgb(127, 127, 127) !important; }`; }; const styleAccents = () => { const primary = cssVariable({ name: "accent-primary", value: "rgb(35, 131, 226)", }), primaryHover = cssVariable({ name: "accent-primary_hover", value: "rgb(0, 117, 211)", }), primaryContrast = cssVariable({ name: "accent-primary_contrast", value: "rgb(255, 255, 255)", }), primaryTransparent = cssVariable({ name: "accent-primary_transparent", value: "rgba(35, 131, 226, 0.14)", }); overrideStyle({ property: "color", variable: primary, specificity: ["value"], }); overrideStyle({ property: "background", variable: primary, specificity: ["value"], cssProps: { fill: primaryContrast, color: primaryContrast, }, }); overrideStyle({ property: "background", variable: primaryHover, specificity: ["value"], cssProps: { fill: primaryContrast, color: primaryContrast, }, }); overrideStyle({ selector: `.notion-table-selection-overlay [style*="border: 2px solid"]`, property: "border-color", variable: primary, specificity: [], }); overrideStyle({ selector: ` [style*="background: ${primary.value}"] svg[style*="fill"], [style*="background-color: ${primary.value}"] svg[style*="fill"] `, property: "fill", variable: primaryContrast, specificity: [], }); overrideStyle({ selector: `[style*="border-radius: 44px;"] > [style*="border-radius: 44px; background: white;"]`, property: "background", variable: primaryContrast, specificity: [], }); overrideStyle({ selector: ` *::selection, .notion-selectable-halo, #notion-app .rdp-day:not(.rdp-day_disabled):not(.rdp-day_selected ):not(.rdp-day_value):not(.rdp-day_start):not(.rdp-day_end):hover, [style*="background: ${primaryTransparent.value.split(".")[0]}."], [style*="background:${primaryTransparent.value.split(".")[0]}."], [style*="background-color: ${primaryTransparent.value.split(".")[0]}."], [style*="background-color:${primaryTransparent.value.split(".")[0]}."] `, property: "background", variable: primaryTransparent, specificity: [], }); const secondary = cssVariable({ name: "accent-secondary", value: "rgb(235, 87, 87)", }), secondaryAliases = [ "rgb(180, 65, 60)", "rgb(211, 79, 67)", "rgb(205, 73, 69)", ], secondaryHover = cssVariable({ name: "accent-secondary_hover", value: "rgba(235, 87, 87, 0.1)", }), secondaryContrast = cssVariable({ name: "accent-secondary_contrast", value: "white", }); overrideStyle({ property: "color", variable: secondary, valueAliases: secondaryAliases, specificity: ["value"], }); overrideStyle({ property: "background", variable: secondary, valueAliases: secondaryAliases, specificity: ["value"], cssProps: { fill: secondaryContrast, color: secondaryContrast, }, postProcessor(selector, cssProps) { return [ `#notion-app .rdp-day_today:not(.rdp-day_selected):not(.rdp-day_value ):not(.rdp-day_start):not(.rdp-day_end)::after, ${selector}`, cssProps, ]; }, }); overrideStyle({ property: "background", variable: secondary, valueAliases: secondaryAliases, specificity: ["value"], cssProps: { fill: secondaryContrast, color: secondaryContrast, }, postProcessor(selector, cssProps) { delete cssProps["background"]; return [ `#notion-app .rdp-day_today:not(.rdp-day_selected):not(.rdp-day_value):not(.rdp-day_start ):not(.rdp-day_end), :is(${selector}) + :is([style*="fill: ${secondaryContrast.value};"], [style*="color: ${secondaryContrast.value};"]), :is(${selector}) :is([style*="fill: ${secondaryContrast.value};"], [style*="color: ${secondaryContrast.value};"])`, cssProps, ]; }, }); overrideStyle({ property: "background", variable: secondaryHover, specificity: ["value"], }); // box-shadows are complicated, style manually cssBody += `.notion-focusable-within:focus-within { box-shadow: var(--theme--accent-primary, ${primary.value}) 0px 0px 0px 1px inset, var(--theme--accent-primary, ${primary.value}) 0px 0px 0px 2px !important; } .notion-focusable:focus-visible { box-shadow: var(--theme--accent-primary, ${primary.value}) 0px 0px 0px 1px inset, var(--theme--accent-primary, ${primary.value}) 0px 0px 0px 2px !important; } ${["box-shadow: rgb(35, 131, 226) 0px 0px 0px 2px inset"] .map((shadow) => { return `[style*="${shadow}"] { ${shadow.replace( /rgba?\([^\)]+\)/g, `var(--theme--accent-primary, ${primary.value})` )} !important; }`; }) .join("")} ${[ "border: 1px solid rgb(110, 54, 48)", "border: 1px solid rgba(235, 87, 87, 0.5)", "border: 2px solid rgb(110, 54, 48)", "border: 2px solid rgb(227, 134, 118)", "border-right: 1px solid rgb(180, 65, 60)", "border-right: 1px solid rgb(211, 79, 67)", ] .map((border) => `[style*="${border}"]`) .join(", ")} { border-color: ${secondary.ref}; }`; }; const styleScrollbars = () => { const scrollbarTrack = cssVariable({ name: "scrollbar-track", value: darkMode ? "rgba(202, 204, 206, 0.04)" : "#EDECE9", }); overrideStyle({ selector: "::-webkit-scrollbar-track", property: "background", variable: scrollbarTrack, specificity: ["mode"], }); overrideStyle({ selector: "::-webkit-scrollbar-corner", property: "background", variable: scrollbarTrack, specificity: ["mode"], }); overrideStyle({ selector: "::-webkit-scrollbar-thumb", property: "background", variable: cssVariable({ name: "scrollbar-thumb", value: darkMode ? "#474c50" : "#D3D1CB", }), specificity: ["mode"], }); overrideStyle({ selector: "::-webkit-scrollbar-thumb:hover", property: "background", variable: cssVariable({ name: "scrollbar-thumb_hover", value: darkMode ? "rgba(202, 204, 206, 0.3)" : "#AEACA6", }), specificity: ["mode"], }); }; const styleCode = () => { overrideStyle({ selector: `.notion-text-block .notion-enable-hover[style*="mono"]`, property: "color", variable: "code-inline_fg", }); overrideStyle({ selector: `.notion-text-block .notion-enable-hover[style*="mono"]`, property: "background", variable: "code-inline_bg", }); overrideStyle({ selector: `.notion-code-block > [style*="mono"]`, property: "color", variable: "code-block_fg", }); overrideStyle({ selector: `.notion-code-block > div > [style*="background"]`, property: "background", variable: "code-block_bg", }); const aliases = {}, code = document.querySelector(".notion-code-block .token"); for (const token of [ // standard tokens from https://prismjs.com/tokens.html "keyword", "builtin", "class-name", "function", "boolean", "number", "string", "char", "symbol", "regex", "url", "operator", "variable", "constant", "property", "punctuation", "important", "comment", "tag", "attr-name", "attr-value", "namespace", "prolog", "doctype", "cdata", "entity", "atrule", "selector", "inserted", "deleted", ]) { code.className = `token ${token}`; overrideStyle({ target: code, selector: `.notion-code-block .token.${token}`, property: "color", variable: `code-${token.replace(/-/g, "_")}`, variableAliases: aliases, specificity: ["mode"], }); } // patch: remove individual backgrounds from prism tokens cssBody += `.token:is( .operator, .entity, .url, :is(.language-css, .style) .string ) { background: transparent !important; }`; }; styleText(); styleBorders(); styleColoredText(); styleBackgrounds(); styleColoredBackgrounds(); styleTooltips(); styleAccents(); styleScrollbars(); styleCode(); console.log( `body${modeSelector} { ${cssRoot} } ${Object.entries(cssRefs) .map(([body, selectors]) => `${[...new Set(selectors)].join(",")}{${body}}`) .join("")} ${cssBody}`.replace(/\s+/g, " ") );