mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-10 15:39:01 +00:00
feat(menu): reactive view navigation
This commit is contained in:
parent
70cd128a46
commit
ac5daf5b73
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* notion-enhancer
|
* notion-enhancer
|
||||||
* (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -38,6 +38,7 @@ const mutationQueue = [],
|
|||||||
mutationQueue.push(...mutations);
|
mutationQueue.push(...mutations);
|
||||||
});
|
});
|
||||||
documentObserver.observe(document.body, {
|
documentObserver.observe(document.body, {
|
||||||
|
attributes: true,
|
||||||
childList: true,
|
childList: true,
|
||||||
subtree: true,
|
subtree: true,
|
||||||
});
|
});
|
||||||
|
@ -25,8 +25,8 @@ const kebabToPascalCase = (string) =>
|
|||||||
.map((child) => (Array.isArray(child) ? hToString(...child) : child))
|
.map((child) => (Array.isArray(child) ? hToString(...child) : child))
|
||||||
.join("")}</${type}>`;
|
.join("")}</${type}>`;
|
||||||
|
|
||||||
// https://gist.github.com/jennyknuth/222825e315d45a738ed9d6e04c7a88d0
|
|
||||||
const encodeSvg = (svg) =>
|
const encodeSvg = (svg) =>
|
||||||
|
// https://gist.github.com/jennyknuth/222825e315d45a738ed9d6e04c7a88d0
|
||||||
svg
|
svg
|
||||||
.replace(
|
.replace(
|
||||||
"<svg",
|
"<svg",
|
||||||
@ -42,118 +42,113 @@ const encodeSvg = (svg) =>
|
|||||||
.replace(/</g, "%3C")
|
.replace(/</g, "%3C")
|
||||||
.replace(/>/g, "%3E")
|
.replace(/>/g, "%3E")
|
||||||
.replace(/\s+/g, " "),
|
.replace(/\s+/g, " "),
|
||||||
svgElements = [
|
presetIcons = ([, icon, mode]) => {
|
||||||
"animate",
|
let svg;
|
||||||
"animateMotion",
|
// manually register i-notion-enhancer: renders the colour
|
||||||
"animateTransform",
|
// version by default, renders the monochrome version when
|
||||||
"circle",
|
// mask mode is requested via i-notion-enhancer?mask
|
||||||
"clipPath",
|
if (icon === "notion-enhancer") {
|
||||||
"defs",
|
svg = mode === "mask" ? iconMonochrome : iconColour;
|
||||||
"desc",
|
} else {
|
||||||
"discard",
|
icon = kebabToPascalCase(icon);
|
||||||
"ellipse",
|
if (!globalThis.lucide[icon]) return;
|
||||||
"feBlend",
|
const [type, props, children] = globalThis.lucide[icon];
|
||||||
"feColorMatrix",
|
svg = hToString(type, props, ...children);
|
||||||
"feComponentTransfer",
|
}
|
||||||
"feComposite",
|
// https://antfu.me/posts/icons-in-pure-css
|
||||||
"feConvolveMatrix",
|
const dataUri = `url("data:image/svg+xml;utf8,${encodeSvg(svg)}")`;
|
||||||
"feDiffuseLighting",
|
if (mode === "auto") mode = undefined;
|
||||||
"feDisplacementMap",
|
mode ??= svg.includes("currentColor") ? "mask" : "bg";
|
||||||
"feDistantLight",
|
return {
|
||||||
"feDropShadow",
|
display: "inline-block",
|
||||||
"feFlood",
|
height: "1em",
|
||||||
"feFuncA",
|
width: "1em",
|
||||||
"feFuncB",
|
...(mode === "mask"
|
||||||
"feFuncG",
|
? {
|
||||||
"feFuncR",
|
mask: `${dataUri} no-repeat`,
|
||||||
"feGaussianBlur",
|
"mask-size": "100% 100%",
|
||||||
"feImage",
|
"background-color": "currentColor",
|
||||||
"feMerge",
|
color: "inherit",
|
||||||
"feMergeNode",
|
}
|
||||||
"feMorphology",
|
: {
|
||||||
"feOffset",
|
background: `${dataUri} no-repeat`,
|
||||||
"fePointLight",
|
"background-size": "100% 100%",
|
||||||
"feSpecularLighting",
|
"background-color": "transparent",
|
||||||
"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",
|
|
||||||
];
|
|
||||||
|
|
||||||
twind.install({
|
twind.install({
|
||||||
rules: [
|
rules: [[/^i-((?:\w|-)+)(?:\?(mask|bg|auto))?$/, presetIcons]],
|
||||||
[
|
|
||||||
/^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" ? 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",
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
variants: [["open", "&[open]"]],
|
variants: [["open", "&[open]"]],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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",
|
||||||
|
];
|
||||||
// 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);
|
||||||
@ -169,7 +164,7 @@ const h = (type, props, ...children) => {
|
|||||||
elem.setAttribute(prop, props[prop]);
|
elem.setAttribute(prop, props[prop]);
|
||||||
} else elem[prop] = props[prop];
|
} else elem[prop] = props[prop];
|
||||||
}
|
}
|
||||||
for (const child of children) elem.append(child);
|
elem.append(...children);
|
||||||
return elem;
|
return elem;
|
||||||
},
|
},
|
||||||
html = htm.bind(h);
|
html = htm.bind(h);
|
||||||
|
@ -45,20 +45,24 @@ export default async (api, db) => {
|
|||||||
|
|
||||||
// menu
|
// menu
|
||||||
|
|
||||||
let $menuModal, $menuFrame;
|
let $menuModal, $menuFrame, _notionTheme;
|
||||||
const setTheme = () => {
|
const updateTheme = (force = false) => {
|
||||||
if (platform !== "browser") $menuFrame.contentWindow.__enhancerApi = api;
|
const darkMode = document.body.classList.contains("dark"),
|
||||||
|
notionTheme = darkMode ? "dark" : "light";
|
||||||
|
if (notionTheme !== _notionTheme || force) {
|
||||||
|
_notionTheme = notionTheme;
|
||||||
const msg = {
|
const msg = {
|
||||||
namespace: "notion-enhancer",
|
namespace: "notion-enhancer",
|
||||||
mode: document.body.classList.contains("dark") ? "dark" : "light",
|
mode: notionTheme,
|
||||||
};
|
};
|
||||||
$menuFrame.contentWindow.postMessage(msg, "*");
|
$menuFrame?.contentWindow.postMessage(msg, "*");
|
||||||
},
|
}
|
||||||
openMenu = () => {
|
};
|
||||||
if ($menuFrame) setTheme();
|
|
||||||
|
const openMenu = () => {
|
||||||
$menuModal?.setAttribute("open", true);
|
$menuModal?.setAttribute("open", true);
|
||||||
},
|
},
|
||||||
closeMenu = () => $menuModal.removeAttribute("open");
|
closeMenu = () => $menuModal?.removeAttribute("open");
|
||||||
|
|
||||||
$menuFrame = html`<iframe
|
$menuFrame = html`<iframe
|
||||||
title="notion-enhancer menu"
|
title="notion-enhancer menu"
|
||||||
@ -66,11 +70,18 @@ export default async (api, db) => {
|
|||||||
class="
|
class="
|
||||||
rounded-[5px] w-[1150px] h-[calc(100vh-100px)]
|
rounded-[5px] w-[1150px] h-[calc(100vh-100px)]
|
||||||
max-w-[calc(100vw-100px)] max-h-[715px] overflow-hidden
|
max-w-[calc(100vw-100px)] max-h-[715px] overflow-hidden
|
||||||
bg-[color:var(--theme--bg-secondary)] drop-shadow-xl
|
bg-[color:var(--theme--bg-primary)] drop-shadow-xl
|
||||||
group-open:(pointer-events-auto opacity-100 scale-100)
|
group-open:(pointer-events-auto opacity-100 scale-100)
|
||||||
transition opacity-0 scale-95
|
transition opacity-0 scale-95
|
||||||
"
|
"
|
||||||
onload=${setTheme}
|
onload=${() => {
|
||||||
|
// pass notion-enhancer api to electron menu process
|
||||||
|
if (platform !== "browser") {
|
||||||
|
$menuFrame.contentWindow.__enhancerApi = api;
|
||||||
|
}
|
||||||
|
// menu relies on updateTheme for render trigger
|
||||||
|
updateTheme(true);
|
||||||
|
}}
|
||||||
></iframe>`;
|
></iframe>`;
|
||||||
$menuModal = html`<div
|
$menuModal = html`<div
|
||||||
class="notion-enhancer--menu-modal group
|
class="notion-enhancer--menu-modal group
|
||||||
@ -115,6 +126,9 @@ export default async (api, db) => {
|
|||||||
});
|
});
|
||||||
document.querySelector(notionSidebar)?.append($menuButton);
|
document.querySelector(notionSidebar)?.append($menuButton);
|
||||||
|
|
||||||
|
addMutationListener("body", () => {
|
||||||
|
if ($menuModal?.hasAttribute("open")) updateTheme();
|
||||||
|
});
|
||||||
onMessage("notion-enhancer", (message) => {
|
onMessage("notion-enhancer", (message) => {
|
||||||
if (message === "open-menu") openMenu();
|
if (message === "open-menu") openMenu();
|
||||||
});
|
});
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
@ -26,70 +28,46 @@ const SidebarSection = ({}, ...children) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SidebarButton = ({ icon, ...props }, ...children) => {
|
const SidebarButton = ({ icon, ...props }, ...children) => {
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi,
|
||||||
return html`<a
|
iconSize =
|
||||||
tabindex="0"
|
icon === "notion-enhancer"
|
||||||
role="button"
|
|
||||||
class="flex select-none cursor-pointer
|
|
||||||
items-center py-[5px] px-[15px] text-[14px] last:mb-[12px]
|
|
||||||
transition hover:bg-[color:var(--theme--bg-hover)]"
|
|
||||||
...${props}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="i-${icon} ${icon === "notion-enhancer"
|
|
||||||
? "w-[18px] h-[18px] ml-px mr-[9px]"
|
? "w-[18px] h-[18px] ml-px mr-[9px]"
|
||||||
: "w-[20px] h-[20px] mr-[8px]"}"
|
: "w-[20px] h-[20px] mr-[8px]",
|
||||||
></i>
|
el = html`<${props.href ? "a" : "button"}
|
||||||
<span class="leading-[20px]">${children}</span>
|
class="flex select-none cursor-pointer w-full
|
||||||
</a>`;
|
items-center py-[5px] px-[15px] text-[14px] last:mb-[12px]
|
||||||
|
transition hover:bg-[color:var(--theme--bg-hover)]"
|
||||||
|
...${props}
|
||||||
|
>
|
||||||
|
<i class="i-${icon} ${iconSize}"></i>
|
||||||
|
<span class="leading-[20px]">${children}</span>
|
||||||
|
<//>`;
|
||||||
|
if (!props.href) {
|
||||||
|
const id = el.innerText;
|
||||||
|
el.onclick ??= () => setState({ view: id });
|
||||||
|
useState(["view"], ([view = "welcome"]) => {
|
||||||
|
const active = view.toLowerCase() === id.toLowerCase();
|
||||||
|
el.style.background = active ? "var(--theme--bg-hover)" : "";
|
||||||
|
el.style.fontWeight = active ? "600" : "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return el;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { Sidebar, SidebarSection, SidebarButton };
|
const View = ({ id }, ...children) => {
|
||||||
|
const { html } = globalThis.__enhancerApi,
|
||||||
|
el = html`<article
|
||||||
|
id=${id}
|
||||||
|
class="notion-enhancer--menu-view h-full
|
||||||
|
overflow-y-auto px-[60px] py-[36px] grow"
|
||||||
|
>
|
||||||
|
${children}
|
||||||
|
</article>`;
|
||||||
|
useState(["view"], ([view = "welcome"]) => {
|
||||||
|
const active = view.toLowerCase() === id.toLowerCase();
|
||||||
|
el.style.display = active ? "" : "none";
|
||||||
|
});
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
|
||||||
// <div
|
export { Sidebar, SidebarSection, SidebarButton, View };
|
||||||
// class="notion-focusable"
|
|
||||||
// role="button"
|
|
||||||
// tabindex="0"
|
|
||||||
// style="
|
|
||||||
// display: flex;
|
|
||||||
// align-items: center;
|
|
||||||
// justify-content: space-between;
|
|
||||||
// padding: 5px 15px;
|
|
||||||
// "
|
|
||||||
// >
|
|
||||||
// <div style="display: flex; align-items: center">
|
|
||||||
// <div
|
|
||||||
// style="
|
|
||||||
// width: 20px;
|
|
||||||
// height: 20px;
|
|
||||||
// margin-right: 8px;
|
|
||||||
// color: rgba(255, 255, 255, 0.81);
|
|
||||||
// fill: rgba(255, 255, 255, 0.81);
|
|
||||||
// "
|
|
||||||
// >
|
|
||||||
// <svg
|
|
||||||
// viewBox="0 0 20 20"
|
|
||||||
// class="settingsIntegration"
|
|
||||||
// style="
|
|
||||||
// width: 20px;
|
|
||||||
// height: 20px;
|
|
||||||
// display: block;
|
|
||||||
// fill: inherit;
|
|
||||||
// flex-shrink: 0;
|
|
||||||
// backface-visibility: hidden;
|
|
||||||
// "
|
|
||||||
// >
|
|
||||||
// <path d="M4.633 9.42h3.154c1.093 0 1.632-.532 1.632-1.656V4.655C9.42 3.532 8.88 3 7.787 3H4.633C3.532 3 3 3.532 3 4.655v3.109c0 1.124.532 1.655 1.633 1.655zm7.58 0h3.162C16.468 9.42 17 8.887 17 7.763V4.655C17 3.532 16.468 3 15.374 3h-3.16c-1.094 0-1.633.532-1.633 1.655v3.109c0 1.124.539 1.655 1.633 1.655zm-7.58-1.251c-.262 0-.382-.135-.382-.405V4.648c0-.27.12-.405.382-.405h3.146c.262 0 .39.135.39.405v3.116c0 .27-.128.405-.39.405H4.633zm7.588 0c-.262 0-.39-.135-.39-.405V4.648c0-.27.128-.405.39-.405h3.146c.262 0 .39.135.39.405v3.116c0 .27-.128.405-.39.405h-3.146zM4.633 17h3.154c1.093 0 1.632-.532 1.632-1.655v-3.109c0-1.124-.539-1.655-1.632-1.655H4.633C3.532 10.58 3 11.112 3 12.236v3.109C3 16.468 3.532 17 4.633 17zm7.58 0h3.162C16.468 17 17 16.468 17 15.345v-3.109c0-1.124-.532-1.655-1.626-1.655h-3.16c-1.094 0-1.633.531-1.633 1.655v3.109c0 1.123.539 1.655 1.633 1.655zm-7.58-1.25c-.262 0-.382-.128-.382-.398v-3.116c0-.277.12-.405.382-.405h3.146c.262 0 .39.128.39.405v3.116c0 .27-.128.397-.39.397H4.633zm7.588 0c-.262 0-.39-.128-.39-.398v-3.116c0-.277.128-.405.39-.405h3.146c.262 0 .39.128.39.405v3.116c0 .27-.128.397-.39.397h-3.146z"></path>
|
|
||||||
// </svg>
|
|
||||||
// </div>
|
|
||||||
// <div
|
|
||||||
// style="
|
|
||||||
// font-size: 14px;
|
|
||||||
// line-height: 20px;
|
|
||||||
// color: rgba(255, 255, 255, 0.81);
|
|
||||||
// "
|
|
||||||
// >
|
|
||||||
// Connections
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </div>;
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
<base target="_blank" />
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>notion-enhancer menu</title>
|
<title>notion-enhancer menu</title>
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Sidebar, SidebarSection, SidebarButton } from "./components.mjs";
|
import { setState, useState } from "./state.mjs";
|
||||||
|
import { Sidebar, SidebarSection, SidebarButton, View } from "./components.mjs";
|
||||||
|
|
||||||
let stylesLoaded = false,
|
let stylesLoaded = false,
|
||||||
sidebarPopulated = false;
|
interfacePopulated = false;
|
||||||
const importApi = async () => {
|
const importApi = async () => {
|
||||||
// chrome extensions run in an isolated execution context
|
// chrome extensions run in an isolated execution context
|
||||||
// but extension:// pages can access chrome apis
|
// but extension:// pages can access chrome apis
|
||||||
@ -25,66 +26,75 @@ const importApi = async () => {
|
|||||||
stylesLoaded = true;
|
stylesLoaded = true;
|
||||||
await import("../../load.mjs");
|
await import("../../load.mjs");
|
||||||
},
|
},
|
||||||
updateTheme = (mode) => {
|
populateInterface = () => {
|
||||||
if (mode === "dark") {
|
|
||||||
document.body.classList.add("dark");
|
|
||||||
} else if (mode === "light") {
|
|
||||||
document.body.classList.remove("dark");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
populateSidebar = () => {
|
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi;
|
||||||
if (!html || sidebarPopulated) return;
|
if (!html || interfacePopulated) return;
|
||||||
sidebarPopulated = true;
|
interfacePopulated = true;
|
||||||
document.body.append(html`<${Sidebar}>
|
const $sidebar = html`<${Sidebar}>
|
||||||
${[
|
${[
|
||||||
"notion-enhancer",
|
"notion-enhancer",
|
||||||
{ icon: "notion-enhancer", title: "Welcome", onClick() {} },
|
{ icon: "notion-enhancer", title: "Welcome" },
|
||||||
{
|
{
|
||||||
icon: "message-circle",
|
icon: "message-circle",
|
||||||
title: "Community",
|
title: "Community",
|
||||||
href: "https://discord.gg/sFWPXtA",
|
href: "https://discord.gg/sFWPXtA",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "clock",
|
icon: "clock",
|
||||||
title: "Changelog",
|
title: "Changelog",
|
||||||
href: "https://notion-enhancer.github.io/about/changelog/",
|
href: "https://notion-enhancer.github.io/about/changelog/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "book",
|
icon: "book",
|
||||||
title: "Documentation",
|
title: "Documentation",
|
||||||
href: "https://notion-enhancer.github.io/",
|
href: "https://notion-enhancer.github.io/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "github",
|
icon: "github",
|
||||||
title: "Source Code",
|
title: "Source Code",
|
||||||
href: "https://github.com/notion-enhancer",
|
href: "https://github.com/notion-enhancer",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "coffee",
|
icon: "coffee",
|
||||||
title: "Sponsor",
|
title: "Sponsor",
|
||||||
href: "https://github.com/sponsors/dragonwocky",
|
href: "https://github.com/sponsors/dragonwocky",
|
||||||
},
|
},
|
||||||
"Settings",
|
"Settings",
|
||||||
{ icon: "sliders-horizontal", title: "Core", onClick() {} },
|
{ icon: "sliders-horizontal", title: "Core" },
|
||||||
{ icon: "palette", title: "Themes", onClick() {} },
|
{ icon: "palette", title: "Themes" },
|
||||||
{ icon: "zap", title: "Extensions", onClick() {} },
|
{ icon: "zap", title: "Extensions" },
|
||||||
{ icon: "plug", title: "Integrations", onClick() {} },
|
{ icon: "plug", title: "Integrations" },
|
||||||
].map((item) => {
|
].map((item) => {
|
||||||
if (typeof item === "string") {
|
if (typeof item === "string") {
|
||||||
return html`<${SidebarSection}>${item}<//>`;
|
return html`<${SidebarSection}>${item}<//>`;
|
||||||
} else {
|
} else {
|
||||||
const { title, ...props } = item;
|
const { title, ...props } = item;
|
||||||
return html`<${SidebarButton} ...${props}>${title}<//>`;
|
return html`<${SidebarButton} ...${props}>${title}<//>`;
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
<//>`);
|
<//>`,
|
||||||
|
$views = [
|
||||||
|
html`<${View} id="welcome">welcome<//>`,
|
||||||
|
html`<${View} id="core">core<//>`,
|
||||||
|
html`<${View} id="themes">themes<//>`,
|
||||||
|
html`<${View} id="extensions">extensions<//>`,
|
||||||
|
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;
|
||||||
updateTheme(event.data?.mode);
|
setState({ theme: event.data?.mode });
|
||||||
await importApi();
|
await importApi();
|
||||||
await importStyles();
|
await importStyles();
|
||||||
populateSidebar();
|
// wait for api globals to be available
|
||||||
|
requestIdleCallback(() => populateInterface());
|
||||||
|
});
|
||||||
|
useState(["theme"], ([mode]) => {
|
||||||
|
if (mode === "dark") {
|
||||||
|
document.body.classList.add("dark");
|
||||||
|
} else if (mode === "light") {
|
||||||
|
document.body.classList.remove("dark");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
21
src/core/menu/state.mjs
Normal file
21
src/core/menu/state.mjs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* notion-enhancer
|
||||||
|
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
const _state = {},
|
||||||
|
_subscribers = [],
|
||||||
|
setState = (state) => {
|
||||||
|
Object.assign(_state, state);
|
||||||
|
const updates = Object.keys(state);
|
||||||
|
_subscribers
|
||||||
|
.filter(([keys]) => updates.some((key) => keys.includes(key)))
|
||||||
|
.forEach(([keys, callback]) => callback(keys.map((key) => _state[key])));
|
||||||
|
},
|
||||||
|
useState = (keys, callback) => {
|
||||||
|
_subscribers.push([keys, callback]);
|
||||||
|
callback(keys.map((key) => _state[key]));
|
||||||
|
};
|
||||||
|
|
||||||
|
export { setState, useState };
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* notion-enhancer
|
* notion-enhancer
|
||||||
* (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ if (isElectron()) {
|
|||||||
const $script = document.createElement("script");
|
const $script = document.createElement("script");
|
||||||
$script.type = "module";
|
$script.type = "module";
|
||||||
$script.src = enhancerUrl("load.mjs");
|
$script.src = enhancerUrl("load.mjs");
|
||||||
document.head.appendChild($script);
|
document.head.append($script);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* notion-enhancer
|
* notion-enhancer
|
||||||
* (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -31,7 +31,7 @@
|
|||||||
const $stylesheet = document.createElement("link");
|
const $stylesheet = document.createElement("link");
|
||||||
$stylesheet.rel = "stylesheet";
|
$stylesheet.rel = "stylesheet";
|
||||||
$stylesheet.href = enhancerUrl(`${mod._src}/${stylesheet}`);
|
$stylesheet.href = enhancerUrl(`${mod._src}/${stylesheet}`);
|
||||||
document.head.appendChild($stylesheet);
|
document.head.append($stylesheet);
|
||||||
}
|
}
|
||||||
if (isMenu) continue;
|
if (isMenu) continue;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user