chore(menu): detect db update by comparing against prev value

- syncs reload btn visibility b/w tabs
- doesn't trigger when switching profiles if identical
This commit is contained in:
dragonwocky 2023-02-03 13:04:12 +11:00
parent ba98ed6412
commit a6e9504b6f
Signed by: dragonwocky
GPG Key ID: 7998D08F7D7BD7A8
10 changed files with 59 additions and 29 deletions

View File

@ -52,18 +52,17 @@ const insertMenu = async (db) => {
let _contentWindow; let _contentWindow;
const sendThemePing = () => { const sendThemePing = () => {
if (!_contentWindow) return;
const darkMode = document.body.classList.contains("dark"), const darkMode = document.body.classList.contains("dark"),
notionTheme = darkMode ? "dark" : "light"; notionTheme = darkMode ? "dark" : "light";
if (renderPing.theme === notionTheme) return; if (renderPing.theme === notionTheme) return;
renderPing.theme = notionTheme; renderPing.theme = notionTheme;
_contentWindow.postMessage(renderPing, "*"); _contentWindow?.postMessage?.(renderPing, "*");
}, },
sendRenderPing = (contentWindow) => { sendRenderPing = (contentWindow) => {
_contentWindow ??= contentWindow; _contentWindow ??= contentWindow;
if (!$modal.hasAttribute("open")) return; if (!$modal.hasAttribute("open")) return;
delete renderPing.theme; delete renderPing.theme;
_contentWindow.focus(); _contentWindow?.focus?.();
sendThemePing(); sendThemePing();
}; };

View File

@ -4,9 +4,10 @@
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
import { useState } from "../state.mjs"; import { setState, useState } from "../state.mjs";
function Checkbox({ _get, _set, ...props }) { function Checkbox({ _get, _set, _requireReload = true, ...props }) {
let _initialValue;
const { html, extendProps } = globalThis.__enhancerApi, const { html, extendProps } = globalThis.__enhancerApi,
$input = html`<input $input = html`<input
type="checkbox" type="checkbox"
@ -21,6 +22,10 @@ function Checkbox({ _get, _set, ...props }) {
useState(["rerender"], async () => { useState(["rerender"], async () => {
const checked = (await _get?.()) ?? $input.checked; const checked = (await _get?.()) ?? $input.checked;
$input.checked = checked; $input.checked = checked;
if (_requireReload) {
_initialValue ??= checked;
if (checked !== _initialValue) setState({ databaseUpdated: true });
}
}); });
return html`<label return html`<label

View File

@ -4,7 +4,7 @@
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
import { useState } from "../state.mjs"; import { setState, useState } from "../state.mjs";
const updateHotkey = (event) => { const updateHotkey = (event) => {
const keys = []; const keys = [];
@ -72,6 +72,7 @@ function Input({
class: className, class: className,
_get, _get,
_set, _set,
_requireReload = true,
...props ...props
}) { }) {
let $filename, $clear; let $filename, $clear;
@ -117,6 +118,7 @@ function Input({
><i class="i-${icon} w-[16px] h-[16px]"></i> ><i class="i-${icon} w-[16px] h-[16px]"></i>
</span>`; </span>`;
let _initialValue;
extendProps($input, { extendProps($input, {
onchange: (event) => { onchange: (event) => {
if (_set && type === "file") { if (_set && type === "file") {
@ -128,8 +130,20 @@ function Input({
if (type === "file") { if (type === "file") {
$filename.innerText = value?.filename || "Upload a file"; $filename.innerText = value?.filename || "Upload a file";
$clear.style.display = value?.filename ? "" : "none"; $clear.style.display = value?.filename ? "" : "none";
} else if ($input.value !== value) $input.value = value; if (_requireReload) {
if (type === "color") updateContrast($input, $icon); _initialValue ??= value?.content || "";
if ((value?.content || "") !== _initialValue) {
setState({ databaseUpdated: true });
}
}
} else {
if ($input.value !== value) $input.value = value;
if (_requireReload) {
_initialValue ??= value;
if (value !== _initialValue) setState({ databaseUpdated: true });
}
if (type === "color") updateContrast($input, $icon);
}
}, },
onkeydown: type === "hotkey" ? updateHotkey : undefined, onkeydown: type === "hotkey" ? updateHotkey : undefined,
oninput: type === "color" ? () => _set?.($input.value) : undefined, oninput: type === "color" ? () => _set?.($input.value) : undefined,

View File

@ -4,7 +4,7 @@
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
import { useState } from "../state.mjs"; import { setState, useState } from "../state.mjs";
import { Popup } from "./Popup.mjs"; import { Popup } from "./Popup.mjs";
function Option({ value, _get, _set }) { function Option({ value, _get, _set }) {
@ -33,7 +33,8 @@ function Option({ value, _get, _set }) {
return $option; return $option;
} }
function Select({ values, _get, _set, ...props }) { function Select({ values, _get, _set, _requireReload = true, ...props }) {
let _initialValue;
const { html } = globalThis.__enhancerApi, const { html } = globalThis.__enhancerApi,
// dir="rtl" overflows to the left during transition // dir="rtl" overflows to the left during transition
$select = html`<div $select = html`<div
@ -45,8 +46,13 @@ function Select({ values, _get, _set, ...props }) {
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]" transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
...${props} ...${props}
></div>`; ></div>`;
useState(["rerender"], () => { useState(["rerender"], async () => {
_get?.().then((value) => ($select.innerText = value)); const value = (await _get?.()) ?? $select.innerText;
$select.innerText = value;
if (_requireReload) {
_initialValue ??= value;
if (value !== _initialValue) setState({ databaseUpdated: true });
}
}); });
return html`<div class="notion-enhancer--menu-select relative"> return html`<div class="notion-enhancer--menu-select relative">

View File

@ -4,9 +4,10 @@
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
import { useState } from "../state.mjs"; import { setState, useState } from "../state.mjs";
function Toggle({ _get, _set, ...props }) { function Toggle({ _get, _set, _requireReload = true, ...props }) {
let _initialValue;
const { html, extendProps } = globalThis.__enhancerApi, const { html, extendProps } = globalThis.__enhancerApi,
$input = html`<input $input = html`<input
type="checkbox" type="checkbox"
@ -19,6 +20,10 @@ function Toggle({ _get, _set, ...props }) {
useState(["rerender"], async () => { useState(["rerender"], async () => {
const checked = (await _get?.()) ?? $input.checked; const checked = (await _get?.()) ?? $input.checked;
$input.checked = checked; $input.checked = checked;
if (_requireReload) {
_initialValue ??= checked;
if (checked !== _initialValue) setState({ databaseUpdated: true });
}
}); });
return html`<div class="notion-enhancer--menu-toggle shrink-0"> return html`<div class="notion-enhancer--menu-toggle shrink-0">

View File

@ -58,7 +58,7 @@ function List({ id, mods, description }) {
} }
} }
} }
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true });
}; };
return html`<${Mod} ...${{ ...mod, _get, _set }} />`; return html`<${Mod} ...${{ ...mod, _get, _set }} />`;
}); });

View File

@ -79,7 +79,7 @@ function Options({ mod }) {
const _get = async () => (await modDatabase(mod.id)).get(opt.key), const _get = async () => (await modDatabase(mod.id)).get(opt.key),
_set = async (value) => { _set = async (value) => {
await (await modDatabase(mod.id)).set(opt.key, value); await (await modDatabase(mod.id)).set(opt.key, value);
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true });
}; };
return html`<${Option} ...${{ _get, _set, ...opt }} />`; return html`<${Option} ...${{ _get, _set, ...opt }} />`;
}); });

View File

@ -33,7 +33,7 @@ function Profile({ id }) {
setActive = async () => { setActive = async () => {
if (await isActive()) return; if (await isActive()) return;
await db.set("activeProfile", id); await db.set("activeProfile", id);
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true });
}; };
const $successName = html`<span const $successName = html`<span
@ -64,7 +64,7 @@ function Profile({ id }) {
res = JSON.parse(res); res = JSON.parse(res);
delete res["profileName"]; delete res["profileName"];
await profile.import(res); await profile.import(res);
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true });
$uploadSuccess.show(); $uploadSuccess.show();
setTimeout(() => $uploadSuccess.hide(), 2000); setTimeout(() => $uploadSuccess.hide(), 2000);
} catch (err) { } catch (err) {
@ -113,10 +113,8 @@ function Profile({ id }) {
const index = profileIds.indexOf(id); const index = profileIds.indexOf(id);
if (index > -1) profileIds.splice(index, 1); if (index > -1) profileIds.splice(index, 1);
await db.set("profileIds", profileIds); await db.set("profileIds", profileIds);
if (await isActive()) { if (await isActive()) await db.remove("activeProfile");
await db.remove("activeProfile"); setState({ rerender: true });
setState({ rerender: true, databaseUpdated: true });
} else setState({ rerender: true });
}, },
$delete = html`<button $delete = html`<button
class="h-[14px] transition duration-[20ms] class="h-[14px] transition duration-[20ms]
@ -155,10 +153,13 @@ function Profile({ id }) {
return html`<li class="flex items-center my-[14px] gap-[8px]" id=${id}> return html`<li class="flex items-center my-[14px] gap-[8px]" id=${id}>
<${Checkbox} <${Checkbox}
...${{ _get: isActive, _set: setActive }} ...${{ _get: isActive, _set: setActive, _requireReload: false }}
onchange=${(event) => (event.target.checked = true)} onchange=${(event) => (event.target.checked = true)}
/> />
<${Input} icon="file-cog" ...${{ _get: getName, _set: setName }} /> <${Input}
icon="file-cog"
...${{ _get: getName, _set: setName, _requireReload: false }}
/>
<${Button} <${Button}
icon="import" icon="import"
variant="sm" variant="sm"

View File

@ -9,8 +9,8 @@ import { Option } from "./Options.mjs";
const privacyPolicy = "https://notion-enhancer.github.io/about/privacy-policy/"; const privacyPolicy = "https://notion-enhancer.github.io/about/privacy-policy/";
function Telemetry() { function Telemetry() {
const { html, platform, version, getMods } = globalThis.__enhancerApi, const { html, platform, version } = globalThis.__enhancerApi,
{ getProfile, isEnabled, initDatabase } = globalThis.__enhancerApi, { getMods, isEnabled, initDatabase } = globalThis.__enhancerApi,
timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const $enabledMods = html`<code></code>`; const $enabledMods = html`<code></code>`;
@ -29,7 +29,7 @@ function Telemetry() {
}, },
_set = async (value) => { _set = async (value) => {
await initDatabase().set("telemetryEnabled", value); await initDatabase().set("telemetryEnabled", value);
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true });
}; };
// todo: actually collect telemetry // todo: actually collect telemetry
@ -44,7 +44,7 @@ function Telemetry() {
(<code>"${version}"</code>), and enabled mods (${$enabledMods}). You can (<code>"${version}"</code>), and enabled mods (${$enabledMods}). You can
opt in or out of telemetry at any time. This setting syncs across opt in or out of telemetry at any time. This setting syncs across
configuration profiles. For more information, read the notion-enhancer's configuration profiles. For more information, read the notion-enhancer's
<a href=${privacyPolicy}>privacy policy</a>.`} <a href=${privacyPolicy} class="ml-[3px]">privacy policy</a>.`}
...${{ _get, _set }} ...${{ _get, _set }}
/>`; />`;
} }

View File

@ -107,7 +107,7 @@ const render = async () => {
const _get = () => isEnabled(mods[i].id), const _get = () => isEnabled(mods[i].id),
_set = async (enabled) => { _set = async (enabled) => {
await setEnabled(mods[i].id, enabled); await setEnabled(mods[i].id, enabled);
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true });
}; };
mods[i].view = html`<${View} id=${mods[i].id}> mods[i].view = html`<${View} id=${mods[i].id}>
<!-- passing an empty options array hides the settings button --> <!-- passing an empty options array hides the settings button -->