mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-12 00:09:03 +00:00
feat(menu): clone notion ui for core settings, add toggles
- reduce size of icons in sidebar - keyboard focus outline - improved distinguishing of attrs vs props - register twind variants from preset-ext
This commit is contained in:
parent
ac5daf5b73
commit
881f69c47d
@ -11,7 +11,7 @@ import { fileURLToPath } from "node:url";
|
|||||||
|
|
||||||
const dependencies = {
|
const dependencies = {
|
||||||
"htm.min.js": "https://unpkg.com/htm@3.1.1/mini/index.js",
|
"htm.min.js": "https://unpkg.com/htm@3.1.1/mini/index.js",
|
||||||
"twind.min.js": "https://unpkg.com/@twind/cdn@1.0.4/cdn.global.js",
|
"twind.min.js": "https://unpkg.com/@twind/cdn@1.0.7/cdn.global.js",
|
||||||
"lucide.min.js": "https://unpkg.com/lucide@0.104.0/dist/umd/lucide.min.js",
|
"lucide.min.js": "https://unpkg.com/lucide@0.104.0/dist/umd/lucide.min.js",
|
||||||
"jscolor.min.js":
|
"jscolor.min.js":
|
||||||
"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.5.1/jscolor.min.js",
|
"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.5.1/jscolor.min.js",
|
||||||
|
@ -79,76 +79,220 @@ const encodeSvg = (svg) =>
|
|||||||
};
|
};
|
||||||
twind.install({
|
twind.install({
|
||||||
rules: [[/^i-((?:\w|-)+)(?:\?(mask|bg|auto))?$/, presetIcons]],
|
rules: [[/^i-((?:\w|-)+)(?:\?(mask|bg|auto))?$/, presetIcons]],
|
||||||
variants: [["open", "&[open]"]],
|
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 = [
|
const svgElements = [
|
||||||
"animate",
|
"animate",
|
||||||
"animateMotion",
|
"animateMotion",
|
||||||
"animateTransform",
|
"animateTransform",
|
||||||
"circle",
|
"circle",
|
||||||
"clipPath",
|
"clipPath",
|
||||||
"defs",
|
"defs",
|
||||||
"desc",
|
"desc",
|
||||||
"discard",
|
"discard",
|
||||||
"ellipse",
|
"ellipse",
|
||||||
"feBlend",
|
"feBlend",
|
||||||
"feColorMatrix",
|
"feColorMatrix",
|
||||||
"feComponentTransfer",
|
"feComponentTransfer",
|
||||||
"feComposite",
|
"feComposite",
|
||||||
"feConvolveMatrix",
|
"feConvolveMatrix",
|
||||||
"feDiffuseLighting",
|
"feDiffuseLighting",
|
||||||
"feDisplacementMap",
|
"feDisplacementMap",
|
||||||
"feDistantLight",
|
"feDistantLight",
|
||||||
"feDropShadow",
|
"feDropShadow",
|
||||||
"feFlood",
|
"feFlood",
|
||||||
"feFuncA",
|
"feFuncA",
|
||||||
"feFuncB",
|
"feFuncB",
|
||||||
"feFuncG",
|
"feFuncG",
|
||||||
"feFuncR",
|
"feFuncR",
|
||||||
"feGaussianBlur",
|
"feGaussianBlur",
|
||||||
"feImage",
|
"feImage",
|
||||||
"feMerge",
|
"feMerge",
|
||||||
"feMergeNode",
|
"feMergeNode",
|
||||||
"feMorphology",
|
"feMorphology",
|
||||||
"feOffset",
|
"feOffset",
|
||||||
"fePointLight",
|
"fePointLight",
|
||||||
"feSpecularLighting",
|
"feSpecularLighting",
|
||||||
"feSpotLight",
|
"feSpotLight",
|
||||||
"feTile",
|
"feTile",
|
||||||
"feTurbulence",
|
"feTurbulence",
|
||||||
"filter",
|
"filter",
|
||||||
"foreignObject",
|
"foreignObject",
|
||||||
"g",
|
"g",
|
||||||
"hatch",
|
"hatch",
|
||||||
"hatchpath",
|
"hatchpath",
|
||||||
"image",
|
"image",
|
||||||
"line",
|
"line",
|
||||||
"linearGradient",
|
"linearGradient",
|
||||||
"marker",
|
"marker",
|
||||||
"mask",
|
"mask",
|
||||||
"metadata",
|
"metadata",
|
||||||
"mpath",
|
"mpath",
|
||||||
"path",
|
"path",
|
||||||
"pattern",
|
"pattern",
|
||||||
"polygon",
|
"polygon",
|
||||||
"polyline",
|
"polyline",
|
||||||
"radialGradient",
|
"radialGradient",
|
||||||
"rect",
|
"rect",
|
||||||
"script",
|
"script",
|
||||||
"set",
|
"set",
|
||||||
"stop",
|
"stop",
|
||||||
"style",
|
"style",
|
||||||
"svg",
|
"svg",
|
||||||
"switch",
|
"switch",
|
||||||
"symbol",
|
"symbol",
|
||||||
"text",
|
"text",
|
||||||
"textPath",
|
"textPath",
|
||||||
"title",
|
"title",
|
||||||
"tspan",
|
"tspan",
|
||||||
"use",
|
"use",
|
||||||
"view",
|
"view",
|
||||||
];
|
],
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
|
||||||
|
htmlAttributes = [
|
||||||
|
"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",
|
||||||
|
];
|
||||||
// html`<div class=${className}></div>`
|
// html`<div class=${className}></div>`
|
||||||
const h = (type, props, ...children) => {
|
const h = (type, props, ...children) => {
|
||||||
children = children.flat(Infinity);
|
children = children.flat(Infinity);
|
||||||
@ -160,7 +304,7 @@ const h = (type, props, ...children) => {
|
|||||||
? document.createElementNS("http://www.w3.org/2000/svg", type)
|
? document.createElementNS("http://www.w3.org/2000/svg", type)
|
||||||
: document.createElement(type);
|
: document.createElement(type);
|
||||||
for (const prop in props ?? {}) {
|
for (const prop in props ?? {}) {
|
||||||
if (["string", "number", "boolean"].includes(typeof props[prop])) {
|
if (htmlAttributes.includes(prop)) {
|
||||||
elem.setAttribute(prop, props[prop]);
|
elem.setAttribute(prop, props[prop]);
|
||||||
} else elem[prop] = props[prop];
|
} else elem[prop] = props[prop];
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ export default async (api, db) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openMenu = () => {
|
const openMenu = () => {
|
||||||
|
updateTheme(true);
|
||||||
$menuModal?.setAttribute("open", true);
|
$menuModal?.setAttribute("open", true);
|
||||||
},
|
},
|
||||||
closeMenu = () => $menuModal?.removeAttribute("open");
|
closeMenu = () => $menuModal?.removeAttribute("open");
|
||||||
|
@ -9,8 +9,8 @@ import { setState, useState } from "./state.mjs";
|
|||||||
const Sidebar = ({}, ...children) => {
|
const Sidebar = ({}, ...children) => {
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi;
|
||||||
return html`<aside
|
return html`<aside
|
||||||
class="notion-enhancer--menu-sidebar h-full w-[250px]
|
class="notion-enhancer--menu-sidebar min-w-[224.14px] max-w-[250px]
|
||||||
overflow-y-auto bg-[color:var(--theme--bg-secondary)]"
|
h-full overflow-y-auto bg-[color:var(--theme--bg-secondary)]"
|
||||||
>
|
>
|
||||||
${children}
|
${children}
|
||||||
</aside>`;
|
</aside>`;
|
||||||
@ -31,8 +31,8 @@ const SidebarButton = ({ icon, ...props }, ...children) => {
|
|||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
iconSize =
|
iconSize =
|
||||||
icon === "notion-enhancer"
|
icon === "notion-enhancer"
|
||||||
? "w-[18px] h-[18px] ml-px mr-[9px]"
|
? "w-[16px] h-[16px] ml-[2px] mr-[10px]"
|
||||||
: "w-[20px] h-[20px] mr-[8px]",
|
: "w-[18px] h-[18px] ml-px mr-[9px]",
|
||||||
el = html`<${props.href ? "a" : "button"}
|
el = html`<${props.href ? "a" : "button"}
|
||||||
class="flex select-none cursor-pointer w-full
|
class="flex select-none cursor-pointer w-full
|
||||||
items-center py-[5px] px-[15px] text-[14px] last:mb-[12px]
|
items-center py-[5px] px-[15px] text-[14px] last:mb-[12px]
|
||||||
@ -70,4 +70,98 @@ const View = ({ id }, ...children) => {
|
|||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { Sidebar, SidebarSection, SidebarButton, View };
|
const TextInput = ({}, ...children) => {};
|
||||||
|
|
||||||
|
const NumberInput = ({}, ...children) => {};
|
||||||
|
|
||||||
|
const HotkeyInput = ({}, ...children) => {};
|
||||||
|
|
||||||
|
const ColorInput = ({}, ...children) => {};
|
||||||
|
|
||||||
|
const FileInput = ({}, ...children) => {};
|
||||||
|
|
||||||
|
const Select = ({}, ...children) => {};
|
||||||
|
|
||||||
|
const Toggle = (props, ..._children) => {
|
||||||
|
const { html } = globalThis.__enhancerApi;
|
||||||
|
return html`<div class="notion-enhancer--menu-toggle shrink-0">
|
||||||
|
<input
|
||||||
|
tabindex="-1"
|
||||||
|
type="checkbox"
|
||||||
|
class="appearance-none w-0 h-0 checked:sibling:children:(
|
||||||
|
bg-[color:var(--theme--accent-primary)] after:translate-x-[12px])"
|
||||||
|
...${props}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
class="w-[30px] h-[18px] transition duration-200
|
||||||
|
rounded-[44px] bg-[color:var(--theme--bg-hover)]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-full h-full rounded-[44px] p-[2px]
|
||||||
|
hover:bg-[color:var(--theme--bg-hover)]
|
||||||
|
transition duration-200 after:(
|
||||||
|
inline-block w-[14px] h-[14px] rounded-[44px]
|
||||||
|
bg-[color:var(--theme--accent-primary\\_contrast)]
|
||||||
|
transition duration-200
|
||||||
|
)"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Option = ({ mod, type, ...props }, ..._children) => {
|
||||||
|
const { html } = globalThis.__enhancerApi,
|
||||||
|
camelToSentenceCase = (string) =>
|
||||||
|
string[0].toUpperCase() +
|
||||||
|
string.replace(/[A-Z]/g, (match) => ` ${match.toLowerCase()}`).slice(1);
|
||||||
|
|
||||||
|
const label = props.label ?? camelToSentenceCase(props.key),
|
||||||
|
description = props.description;
|
||||||
|
if (type === "heading") {
|
||||||
|
return html`<h2
|
||||||
|
class="notion-enhancer--menu-heading font-semibold
|
||||||
|
mb-[16px] mt-[48px] first:mt-0 pb-[12px] text-[16px]
|
||||||
|
border-b border-b-[color:var(--theme--fg-border)]"
|
||||||
|
>
|
||||||
|
${label}
|
||||||
|
</h2>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = `${mod}-${props.key}`;
|
||||||
|
switch (type) {
|
||||||
|
// case "text":
|
||||||
|
// break;
|
||||||
|
// case "number":
|
||||||
|
// break;
|
||||||
|
// case "hotkey":
|
||||||
|
// break;
|
||||||
|
// case "color":
|
||||||
|
// break;
|
||||||
|
// case "file":
|
||||||
|
// break;
|
||||||
|
// case "select":
|
||||||
|
// break;
|
||||||
|
// case "toggle":
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<label
|
||||||
|
class="notion-enhancer--menu-option mb-[18px]
|
||||||
|
flex items-center justify-between cursor-pointer"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col mr-[10%]" for=${id}>
|
||||||
|
<h3 class="text-[14px] mb-[2px] mt-0">${label}</h3>
|
||||||
|
<p
|
||||||
|
class="text-[12px] leading-[16px]
|
||||||
|
text-[color:var(--theme--fg-secondary)]"
|
||||||
|
innerHTML=${description}
|
||||||
|
></p>
|
||||||
|
</div>
|
||||||
|
<${Toggle} id=${id} />
|
||||||
|
</label>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Sidebar, SidebarSection, SidebarButton, View, Toggle, Option };
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
::selection {
|
::selection {
|
||||||
background: var(--theme--accent-primary_transparent);
|
background: var(--theme--accent-primary_transparent);
|
||||||
}
|
}
|
||||||
|
*:focus-visible {
|
||||||
|
outline: 3px solid var(--theme--accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
@ -24,5 +27,10 @@
|
|||||||
background: var(--theme--scrollbar-thumb_hover) !important;
|
background: var(--theme--scrollbar-thumb_hover) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
|
.notion-enhancer--menu-option a {
|
||||||
*,::after,::before{box-sizing:border-box}html{-moz-tab-size:4;tab-size:4}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}body{font-family:system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji'}hr{height:0;color:inherit}abbr[title]{text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Consolas,'Liberation Mono',Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}::-moz-focus-inner{border-style:none;padding:0}:-moz-focusring{outline:1px dotted ButtonText}:-moz-ui-invalid{box-shadow:none}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}
|
text-decoration: underline;
|
||||||
|
transition: 100ms ease-in;
|
||||||
|
}
|
||||||
|
.notion-enhancer--menu-option a:hover {
|
||||||
|
color: var(--theme--accent-secondary);
|
||||||
|
}
|
||||||
|
@ -5,96 +5,98 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { setState, useState } from "./state.mjs";
|
import { setState, useState } from "./state.mjs";
|
||||||
import { Sidebar, SidebarSection, SidebarButton, View } from "./components.mjs";
|
import {
|
||||||
|
Sidebar,
|
||||||
|
SidebarSection,
|
||||||
|
SidebarButton,
|
||||||
|
View,
|
||||||
|
Option,
|
||||||
|
} from "./components.mjs";
|
||||||
|
|
||||||
let stylesLoaded = false,
|
let renderStarted;
|
||||||
interfacePopulated = false;
|
const render = async () => {
|
||||||
const importApi = async () => {
|
const { html, getCore } = globalThis.__enhancerApi;
|
||||||
// chrome extensions run in an isolated execution context
|
if (!html || !getCore || renderStarted) return;
|
||||||
// but extension:// pages can access chrome apis
|
renderStarted = true;
|
||||||
// ∴ notion-enhancer api is imported directly
|
|
||||||
if (typeof globalThis.__enhancerApi === "undefined") {
|
const core = await getCore();
|
||||||
await import("../../api/browser.js");
|
|
||||||
}
|
const $sidebar = html`<${Sidebar}>
|
||||||
// in electron this isn't necessary, as a) scripts are
|
${[
|
||||||
// not running in an isolated execution context and b)
|
"notion-enhancer",
|
||||||
// the notion:// protocol csp bypass allows scripts to
|
{ icon: "notion-enhancer", title: "Welcome" },
|
||||||
// set iframe globals via $iframe.contentWindow
|
{
|
||||||
},
|
icon: "message-circle",
|
||||||
importStyles = async () => {
|
title: "Community",
|
||||||
if (stylesLoaded) return false;
|
href: "https://discord.gg/sFWPXtA",
|
||||||
stylesLoaded = true;
|
},
|
||||||
await import("../../load.mjs");
|
{
|
||||||
},
|
icon: "clock",
|
||||||
populateInterface = () => {
|
title: "Changelog",
|
||||||
const { html } = globalThis.__enhancerApi;
|
href: "https://notion-enhancer.github.io/about/changelog/",
|
||||||
if (!html || interfacePopulated) return;
|
},
|
||||||
interfacePopulated = true;
|
{
|
||||||
const $sidebar = html`<${Sidebar}>
|
icon: "book",
|
||||||
${[
|
title: "Documentation",
|
||||||
"notion-enhancer",
|
href: "https://notion-enhancer.github.io/",
|
||||||
{ icon: "notion-enhancer", title: "Welcome" },
|
},
|
||||||
{
|
{
|
||||||
icon: "message-circle",
|
icon: "github",
|
||||||
title: "Community",
|
title: "Source Code",
|
||||||
href: "https://discord.gg/sFWPXtA",
|
href: "https://github.com/notion-enhancer",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "clock",
|
icon: "coffee",
|
||||||
title: "Changelog",
|
title: "Sponsor",
|
||||||
href: "https://notion-enhancer.github.io/about/changelog/",
|
href: "https://github.com/sponsors/dragonwocky",
|
||||||
},
|
},
|
||||||
{
|
"Settings",
|
||||||
icon: "book",
|
{ icon: "sliders-horizontal", title: "Core" },
|
||||||
title: "Documentation",
|
{ icon: "palette", title: "Themes" },
|
||||||
href: "https://notion-enhancer.github.io/",
|
{ icon: "zap", title: "Extensions" },
|
||||||
},
|
{ icon: "plug", title: "Integrations" },
|
||||||
{
|
].map((item) => {
|
||||||
icon: "github",
|
if (typeof item === "string") {
|
||||||
title: "Source Code",
|
return html`<${SidebarSection}>${item}<//>`;
|
||||||
href: "https://github.com/notion-enhancer",
|
} else {
|
||||||
},
|
const { title, ...props } = item;
|
||||||
{
|
return html`<${SidebarButton} ...${props}>${title}<//>`;
|
||||||
icon: "coffee",
|
}
|
||||||
title: "Sponsor",
|
})}
|
||||||
href: "https://github.com/sponsors/dragonwocky",
|
<//>`,
|
||||||
},
|
$views = [
|
||||||
"Settings",
|
html`<${View} id="welcome">welcome<//>`,
|
||||||
{ icon: "sliders-horizontal", title: "Core" },
|
html`<${View} id="core">
|
||||||
{ icon: "palette", title: "Themes" },
|
${core.options.map(
|
||||||
{ icon: "zap", title: "Extensions" },
|
(opt) => html`<${Option} mod=${core.id} ...${opt} />`
|
||||||
{ icon: "plug", title: "Integrations" },
|
)}
|
||||||
].map((item) => {
|
|
||||||
if (typeof item === "string") {
|
|
||||||
return html`<${SidebarSection}>${item}<//>`;
|
|
||||||
} else {
|
|
||||||
const { title, ...props } = item;
|
|
||||||
return html`<${SidebarButton} ...${props}>${title}<//>`;
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
<//>`,
|
<//>`,
|
||||||
$views = [
|
html`<${View} id="themes">themes<//>`,
|
||||||
html`<${View} id="welcome">welcome<//>`,
|
html`<${View} id="extensions">extensions<//>`,
|
||||||
html`<${View} id="core">core<//>`,
|
html`<${View} id="integrations">integrations<//>`,
|
||||||
html`<${View} id="themes">themes<//>`,
|
];
|
||||||
html`<${View} id="extensions">extensions<//>`,
|
document.body.append($sidebar, ...$views);
|
||||||
html`<${View} id="integrations">integrations<//>`,
|
};
|
||||||
];
|
|
||||||
document.body.append($sidebar, ...$views);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("message", async (event) => {
|
window.addEventListener("message", async (event) => {
|
||||||
if (event.data?.namespace !== "notion-enhancer") return;
|
if (event.data?.namespace !== "notion-enhancer") return;
|
||||||
setState({ theme: event.data?.mode });
|
setState({ theme: event.data?.mode });
|
||||||
await importApi();
|
// chrome extensions run in an isolated execution context
|
||||||
await importStyles();
|
// but extension:// pages can access chrome apis
|
||||||
|
// ∴ notion-enhancer api is imported directly
|
||||||
|
if (typeof globalThis.__enhancerApi === "undefined") {
|
||||||
|
await import("../../api/browser.js");
|
||||||
|
// in electron this isn't necessary, as a) scripts are
|
||||||
|
// not running in an isolated execution context and b)
|
||||||
|
// the notion:// protocol csp bypass allows scripts to
|
||||||
|
// set iframe globals via $iframe.contentWindow
|
||||||
|
}
|
||||||
|
// load stylesheets from enabled themes
|
||||||
|
await import("../../load.mjs");
|
||||||
// wait for api globals to be available
|
// wait for api globals to be available
|
||||||
requestIdleCallback(() => populateInterface());
|
requestIdleCallback(render);
|
||||||
});
|
});
|
||||||
useState(["theme"], ([mode]) => {
|
useState(["theme"], ([mode]) => {
|
||||||
if (mode === "dark") {
|
if (mode === "dark") document.body.classList.add("dark");
|
||||||
document.body.classList.add("dark");
|
if (mode === "light") document.body.classList.remove("dark");
|
||||||
} else if (mode === "light") {
|
|
||||||
document.body.classList.remove("dark");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
15
src/load.mjs
15
src/load.mjs
@ -7,11 +7,13 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
console.log("notion-enhancer: loading...");
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const { enhancerUrl } = globalThis.__enhancerApi,
|
const { enhancerUrl } = globalThis.__enhancerApi,
|
||||||
isMenu = location.href.startsWith(enhancerUrl("/core/menu/index.html")),
|
isMenu = location.href.startsWith(enhancerUrl("/core/menu/index.html")),
|
||||||
pageLoaded = /(^\/$)|((-|\/)[0-9a-f]{32}((\?.+)|$))/.test(location.pathname),
|
pageLoaded = /(^\/$)|((-|\/)[0-9a-f]{32}((\?.+)|$))/.test(location.pathname),
|
||||||
signedIn = localStorage["LRU:KeyValueStore2:current-user-id"];
|
signedIn = localStorage["LRU:KeyValueStore2:current-user-id"];
|
||||||
if (!isMenu && !(signedIn && pageLoaded)) return;
|
if (!isMenu && !(signedIn && pageLoaded)) return;
|
||||||
|
|
||||||
await import("./vendor/twind.min.js");
|
await import("./vendor/twind.min.js");
|
||||||
@ -25,6 +27,9 @@
|
|||||||
|
|
||||||
for (const mod of await getMods()) {
|
for (const mod of await getMods()) {
|
||||||
if (!(await isEnabled(mod.id))) continue;
|
if (!(await isEnabled(mod.id))) continue;
|
||||||
|
const isTheme = mod._src.startsWith("themes/"),
|
||||||
|
isCore = mod._src === "core";
|
||||||
|
if (isMenu && !(isTheme || isCore)) continue;
|
||||||
|
|
||||||
// clientStyles
|
// clientStyles
|
||||||
for (let stylesheet of mod.clientStyles ?? []) {
|
for (let stylesheet of mod.clientStyles ?? []) {
|
||||||
@ -33,9 +38,9 @@
|
|||||||
$stylesheet.href = enhancerUrl(`${mod._src}/${stylesheet}`);
|
$stylesheet.href = enhancerUrl(`${mod._src}/${stylesheet}`);
|
||||||
document.head.append($stylesheet);
|
document.head.append($stylesheet);
|
||||||
}
|
}
|
||||||
if (isMenu) continue;
|
|
||||||
|
|
||||||
// clientScripts
|
// clientScripts
|
||||||
|
if (isMenu) continue;
|
||||||
const options = await optionDefaults(mod.id),
|
const options = await optionDefaults(mod.id),
|
||||||
db = initDatabase([await getProfile(), mod.id], options);
|
db = initDatabase([await getProfile(), mod.id], options);
|
||||||
for (let script of mod.clientScripts ?? []) {
|
for (let script of mod.clientScripts ?? []) {
|
||||||
@ -43,4 +48,6 @@
|
|||||||
script.default(globalThis.__enhancerApi, db);
|
script.default(globalThis.__enhancerApi, db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("notion-enhancer: ready");
|
||||||
})();
|
})();
|
||||||
|
2
src/vendor/twind.min.js
vendored
2
src/vendor/twind.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user