feat(core): implement dev mode toggle in electron app

+ refactor: merge components/ into islands/ for consistency
This commit is contained in:
dragonwocky 2023-08-04 13:13:06 +10:00
parent e762e68f7f
commit 4f07420c4a
Signed by: dragonwocky
GPG Key ID: 7998D08F7D7BD7A8
28 changed files with 143 additions and 146 deletions

View File

@ -4,25 +4,26 @@
* (https://notion-enhancer.github.io/) under the MIT license
*/
import { checkForUpdate } from "./update.mjs";
import { sendTelemetryPing } from "./telemetry.mjs";
import { Frame, Modal, Button } from "./components.mjs";
import { checkForUpdate } from "./updateCheck.mjs";
import { sendTelemetryPing } from "./sendTelemetry.mjs";
import { Modal, Frame } from "./islands/Modal.mjs";
import { MenuButton } from "./islands/MenuButton.mjs";
const doThemeOverride = async (db) => {
const shouldLoadThemeOverrides = async (db) => {
const { getMods, isEnabled } = globalThis.__enhancerApi,
loadThemeOverrides = await db.get("loadThemeOverrides");
if (loadThemeOverrides === "Enabled") return true;
if (loadThemeOverrides === "Disabled") return false;
// prettier-ignore
// loadThemeOverrides === "Auto"
return (await getMods(async (mod) => {
// loadThemeOverrides === "Auto"
if (!mod._src.startsWith("themes/")) return false;
return await isEnabled(mod.id);
})).length;
},
overrideThemes = async (db) => {
loadThemeOverrides = async (db) => {
const { html, enhancerUrl } = globalThis.__enhancerApi;
if (!(await doThemeOverride(db))) return;
if (!(await shouldLoadThemeOverrides(db))) return;
document.head.append(html`<link
rel="stylesheet"
href=${enhancerUrl("core/theme.css")}
@ -37,36 +38,36 @@ const doThemeOverride = async (db) => {
</style>`);
};
const initMenu = async (db) => {
const insertMenu = async (db) => {
const notionSidebar = `.notion-sidebar-container .notion-sidebar > :nth-child(3) > div > :nth-child(2)`,
notionSettingsAndMembers = `${notionSidebar} > [role="button"]:nth-child(3)`,
{ html, addKeyListener, addMutationListener } = globalThis.__enhancerApi,
{ platform, enhancerUrl, onMessage } = globalThis.__enhancerApi,
menuButtonIconStyle = await db.get("menuButtonIconStyle"),
openMenuHotkey = await db.get("openMenuHotkey"),
renderPing = {
menuPing = {
channel: "notion-enhancer",
hotkey: openMenuHotkey,
icon: menuButtonIconStyle,
};
let _contentWindow;
const sendThemePing = () => {
const updateMenuTheme = () => {
const darkMode = document.body.classList.contains("dark"),
notionTheme = darkMode ? "dark" : "light";
if (renderPing.theme === notionTheme) return;
renderPing.theme = notionTheme;
_contentWindow?.postMessage?.(renderPing, "*");
if (menuPing.theme === notionTheme) return;
menuPing.theme = notionTheme;
_contentWindow?.postMessage?.(menuPing, "*");
},
sendRenderPing = (contentWindow) => {
triggerMenuRender = (contentWindow) => {
_contentWindow ??= contentWindow;
if (!$modal.hasAttribute("open")) return;
delete renderPing.theme;
_contentWindow?.focus?.();
sendThemePing();
delete menuPing.theme;
updateMenuTheme();
};
const $modal = html`<${Modal} onopen=${sendRenderPing}>
const $modal = html`<${Modal} onopen=${triggerMenuRender}>
<${Frame}
title="notion-enhancer menu"
src="${enhancerUrl("core/menu/index.html")}"
@ -76,52 +77,50 @@ const initMenu = async (db) => {
const apiKey = "__enhancerApi";
this.contentWindow[apiKey] = globalThis[apiKey];
}
sendRenderPing(this.contentWindow);
triggerMenuRender(this.contentWindow);
}}
/>
<//>`,
$button = html`<${Button}
$button = html`<${MenuButton}
onclick=${$modal.open}
notifications=${(await checkForUpdate()) ? 1 : 0}
themeOverridesLoaded=${await doThemeOverride(db)}
themeOverridesLoaded=${await shouldLoadThemeOverrides(db)}
icon="notion-enhancer${menuButtonIconStyle === "Monochrome"
? "?mask"
: " text-[16px]"}"
>notion-enhancer
<//>`;
const insertMenu = () => {
const appendToDom = () => {
if (!document.contains($modal)) document.body.append($modal);
if (!document.querySelector(notionSidebar)?.contains($button)) {
document.querySelector(notionSettingsAndMembers)?.after($button);
}
};
addMutationListener(notionSidebar, insertMenu);
insertMenu();
addMutationListener("body", sendThemePing);
window.addEventListener("focus", sendRenderPing);
addMutationListener(notionSidebar, appendToDom);
addMutationListener("body", updateMenuTheme);
appendToDom();
addKeyListener(openMenuHotkey, (event) => {
event.preventDefault();
$modal.open();
});
window.addEventListener("focus", triggerMenuRender);
window.addEventListener("message", (event) => {
// from embedded menu
if (event.data?.channel !== "notion-enhancer") return;
if (event.data?.action === "close-menu") $modal.close();
if (event.data?.action === "open-menu") $modal.open();
});
onMessage("notion-enhancer", (message) => {
// from worker
if (message === "open-menu") $modal.open();
});
};
export default async (api, db) => {
const { sendMessage } = globalThis.__enhancerApi;
await Promise.all([
overrideThemes(db),
export default async (api, db) =>
Promise.all([
insertMenu(db),
insertCustomStyles(db),
initMenu(db),
loadThemeOverrides(db),
sendTelemetryPing(),
]);
sendMessage("notion-enhancer", "load-complete");
};
]).then(() => api.sendMessage("notion-enhancer", "load-complete"));

View File

@ -1,33 +0,0 @@
{
"__comment": "pseudo-mod to allow configuration of api-provided components",
"name": "components",
"id": "36a2ffc9-27ff-480e-84a7-c7700a7d232d",
"version": "0.2.0",
"description": "shared notion-style elements.",
"tags": ["core"],
"authors": [
{
"name": "dragonwocky",
"email": "thedragonring.bod@gmail.com",
"homepage": "https://dragonwocky.me/",
"avatar": "https://dragonwocky.me/avatar.jpg"
},
{
"name": "CloudHill",
"email": "rh.cloudhill@gmail.com",
"homepage": "https://github.com/CloudHill",
"avatar": "https://avatars.githubusercontent.com/u/54142180"
}
],
"js": {},
"css": {},
"options": [
{
"type": "hotkey",
"key": "panel.hotkey",
"label": "toggle panel hotkey",
"value": "Ctrl+Alt+\\",
"tooltip": "**opens/closes the side panel in notion** if a mod that uses it has been enabled"
}
]
}

View File

@ -0,0 +1,43 @@
/**
* notion-enhancer
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
function MenuButton(
{ icon, notifications, themeOverridesLoaded, ...props },
...children
) {
const { html, extendProps } = globalThis.__enhancerApi;
extendProps(props, {
tabindex: 0,
role: "button",
class: `notion-enhancer--menu-button
flex select-none cursor-pointer rounded-[3px]
text-[14px] my-px mx-[4px] py-[2px] px-[10px]
transition hover:bg-[color:var(--theme--bg-hover)]`,
});
return html`<div ...${props}>
<div class="flex items-center justify-center w-[22px] h-[22px] mr-[8px]">
<i class="i-${icon}"></i>
</div>
<div>${children}</div>
<div class="ml-auto my-auto${notifications > 0 ? "" : " hidden"}">
<!-- accents are squashed into one variable for theming:
use rgb to match notion if overrides not loaded -->
<div
class="flex justify-center w-[16px] h-[16px] font-semibold
text-([10px] [color:var(--theme--accent-secondary\\_contrast)])
bg-[color:var(--theme--accent-secondary)] rounded-[3px] mb-[2px]
dark:bg-[color:${themeOverridesLoaded
? "var(--theme--accent-secondary)"
: "rgb(180,65,60)"}]"
>
<span class="ml-[-0.5px]">${notifications}</span>
</div>
</div>
</div>`;
}
export { MenuButton };

View File

@ -4,18 +4,6 @@
* (https://notion-enhancer.github.io/) under the MIT license
*/
function Frame(props) {
const { html, extendProps } = globalThis.__enhancerApi;
extendProps(props, {
class: `rounded-[5px] w-[1150px] h-[calc(100vh-100px)]
max-w-[calc(100vw-100px)] max-h-[715px] overflow-hidden
bg-[color:var(--theme--bg-primary)] drop-shadow-xl
group-open:(pointer-events-auto opacity-100 scale-100)
transition opacity-0 scale-95`,
});
return html`<iframe ...${props}></iframe>`;
}
function Modal(props, ...children) {
const { html, extendProps, addKeyListener } = globalThis.__enhancerApi;
extendProps(props, {
@ -56,40 +44,16 @@ function Modal(props, ...children) {
return $modal;
}
function Button(
{ icon, notifications, themeOverridesLoaded, ...props },
...children
) {
function Frame(props) {
const { html, extendProps } = globalThis.__enhancerApi;
extendProps(props, {
tabindex: 0,
role: "button",
class: `notion-enhancer--menu-button
flex select-none cursor-pointer rounded-[3px]
text-[14px] my-px mx-[4px] py-[2px] px-[10px]
transition hover:bg-[color:var(--theme--bg-hover)]`,
class: `rounded-[5px] w-[1150px] h-[calc(100vh-100px)]
max-w-[calc(100vw-100px)] max-h-[715px] overflow-hidden
bg-[color:var(--theme--bg-primary)] drop-shadow-xl
group-open:(pointer-events-auto opacity-100 scale-100)
transition opacity-0 scale-95`,
});
return html`<div ...${props}>
<div class="flex items-center justify-center w-[22px] h-[22px] mr-[8px]">
<i class="i-${icon}"></i>
</div>
<div>${children}</div>
<div class="ml-auto my-auto${notifications > 0 ? "" : " hidden"}">
<!-- accents are squashed into one variable for theming:
use rgb to match notion if overrides not loaded -->
<div
class="flex justify-center w-[16px] h-[16px] font-semibold
text-([10px] [color:var(--theme--accent-secondary\\_contrast)])
bg-[color:var(--theme--accent-secondary)] rounded-[3px] mb-[2px]
dark:bg-[color:${themeOverridesLoaded
? "var(--theme--accent-secondary)"
: "rgb(180,65,60)"}]"
>
<span class="ml-[-0.5px]">${notifications}</span>
</div>
</div>
</div>`;
return html`<iframe ...${props}></iframe>`;
}
export { Frame, Modal, Button };
export { Modal, Frame };

View File

@ -0,0 +1,12 @@
/**
* notion-enhancer
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
function Panel(props) {
const { html, extendProps } = globalThis.__enhancerApi;
return html`<iframe ...${props}></iframe>`;
}
export { Panel };

View File

@ -4,9 +4,9 @@
* (https://notion-enhancer.github.io/) under the MIT license
*/
import { Popup } from "../components/Popup.mjs";
import { Button } from "../components/Button.mjs";
import { Description } from "../components/Description.mjs";
import { Popup } from "./Popup.mjs";
import { Button } from "./Button.mjs";
import { Description } from "./Description.mjs";
import { useState } from "../state.mjs";
const updateGuide =

View File

@ -5,7 +5,7 @@
*/
import { setState, useState } from "../state.mjs";
import { Button } from "../components/Button.mjs";
import { Button } from "./Button.mjs";
function Footer({ categories }) {
const { html, reloadApp } = globalThis.__enhancerApi,

View File

@ -5,8 +5,8 @@
*/
import { setState } from "../state.mjs";
import { Description } from "../components/Description.mjs";
import { Input } from "../components/Input.mjs";
import { Description } from "./Description.mjs";
import { Input } from "./Input.mjs";
import { Mod } from "./Mod.mjs";
function Search({ items, itemType }) {

View File

@ -5,8 +5,8 @@
*/
import { setState } from "../state.mjs";
import { Description } from "../components/Description.mjs";
import { Toggle } from "../components/Toggle.mjs";
import { Description } from "./Description.mjs";
import { Toggle } from "./Toggle.mjs";
function Mod({
id,

View File

@ -4,11 +4,11 @@
* (https://notion-enhancer.github.io/) under the MIT license
*/
import { Heading } from "../components/Heading.mjs";
import { Description } from "../components/Description.mjs";
import { Checkbox } from "../components/Checkbox.mjs";
import { Button } from "../components/Button.mjs";
import { Tile } from "../components/Tile.mjs";
import { Heading } from "./Heading.mjs";
import { Description } from "./Description.mjs";
import { Checkbox } from "./Checkbox.mjs";
import { Button } from "./Button.mjs";
import { Tile } from "./Tile.mjs";
import { setState, useState } from "../state.mjs";
const privacyPolicy = "https://notion-enhancer.github.io/about/privacy-policy/",

View File

@ -5,11 +5,11 @@
*/
import { setState } from "../state.mjs";
import { Heading } from "../components/Heading.mjs";
import { Description } from "../components/Description.mjs";
import { Input } from "../components/Input.mjs";
import { Select } from "../components/Select.mjs";
import { Toggle } from "../components/Toggle.mjs";
import { Heading } from "./Heading.mjs";
import { Description } from "./Description.mjs";
import { Input } from "./Input.mjs";
import { Select } from "./Select.mjs";
import { Toggle } from "./Toggle.mjs";
const camelToSentenceCase = (string) =>
string[0].toUpperCase() +
@ -22,16 +22,18 @@ const camelToSentenceCase = (string) =>
// ignore platform-specific options
if (opt.platforms && !opt.platforms.includes(platform)) return options;
// replace consective headings
opt.autoremove ??= true;
opt._autoremoveIfSectionEmpty ??= true;
const prev = options[options.length - 1],
canReplacePrev = prev?.autoremove && prev?.type === opt.type;
canReplacePrev =
prev?._autoremoveIfSectionEmpty && prev?.type === opt.type;
if (opt.type === "heading" && canReplacePrev) {
options[options.length - 1] = opt;
} else options.push(opt);
return options;
}, []);
// remove trailing heading
return options.at(-1)?.type === "heading" && options.at(-1)?.autoremove
return options.at(-1)?.type === "heading" &&
options.at(-1)?._autoremoveIfSectionEmpty
? options.slice(0, -1)
: options;
};

View File

@ -5,12 +5,12 @@
*/
import { setState, useState } from "../state.mjs";
import { Heading } from "../components/Heading.mjs";
import { Description } from "../components/Description.mjs";
import { Checkbox } from "../components/Checkbox.mjs";
import { Button } from "../components/Button.mjs";
import { Input } from "../components/Input.mjs";
import { Popup } from "../components/Popup.mjs";
import { Heading } from "./Heading.mjs";
import { Description } from "./Description.mjs";
import { Checkbox } from "./Checkbox.mjs";
import { Button } from "./Button.mjs";
import { Input } from "./Input.mjs";
import { Popup } from "./Popup.mjs";
function Profile({ id }) {
const { html, getProfile, initDatabase } = globalThis.__enhancerApi,

View File

@ -5,7 +5,7 @@
*/
import { setState, useState } from "../state.mjs";
import { Description } from "../components/Description.mjs";
import { Description } from "./Description.mjs";
function SidebarHeading({}, ...children) {
const { html } = globalThis.__enhancerApi;

View File

@ -4,7 +4,7 @@
* (https://notion-enhancer.github.io/) under the MIT license
*/
import { collectTelemetryData } from "../../telemetry.mjs";
import { collectTelemetryData } from "../../sendTelemetry.mjs";
import { useState, setState } from "../state.mjs";
import { Option } from "./Options.mjs";

View File

@ -5,7 +5,7 @@
*/
import { setState, useState } from "./state.mjs";
import { checkForUpdate, isDevelopmentBuild } from "../update.mjs";
import { checkForUpdate, isDevelopmentBuild } from "../updateCheck.mjs";
import { Sidebar } from "./islands/Sidebar.mjs";
import { Footer } from "./islands/Footer.mjs";
import { Banner } from "./islands/Banner.mjs";

View File

@ -1,7 +1,7 @@
{
"id": "0f0bf8b6-eae6-4273-b307-8fc43f2ee082",
"name": "notion-enhancer",
"version": "0.11.1-dev",
"version": "0.11.1",
"description": "an enhancer/customiser for the all-in-one productivity workspace notion.so",
"tags": ["core"],
"authors": [
@ -35,7 +35,7 @@
{
"type": "select",
"key": "loadThemeOverrides",
"description": "Loads the styling required for a theme to customise Notion's interface. Disabling this will increase client performance.",
"description": "Loads the styling required for a theme to customise Notion's interface. Disabling this may increase client performance, but will also disable all themes.",
"values": ["Auto", "Enabled", "Disabled"]
},
{
@ -47,16 +47,17 @@
{
"type": "heading",
"label": "Advanced",
"autoremove": false
"_autoremoveIfSectionEmpty": false
},
{
"type": "toggle",
"key": "developerMode",
"description": "Activates built-in debugging tools accessible through the application menu in desktop environments and restores access to the DevTools console via the <kbd>Ctrl+Shift+I</kbd> hotkey.",
"description": "Activates built-in debugging tools accessible through the application menu.",
"platforms": ["linux", "win32", "darwin"],
"value": false
}
],
"clientStyles": ["variables.css"],
"clientScripts": ["client.mjs"],
"electronScripts": []
"electronScripts": [{ "source": "notionConfig.cjs", "target": "config.js" }]
}

View File

@ -0,0 +1,9 @@
/**
* notion-enhancer
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
module.exports = async (api, db, __exports, __eval) => {
if (await db.get("developerMode")) __exports.default.env = "development";
};