mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-11 15:59:03 +00:00
feat(menu): option values update on view change/page focus, animate view changes
This commit is contained in:
parent
765e7b738c
commit
c95d96cd8e
@ -78,10 +78,15 @@ const initDatabase = (namespace, fallbacks = {}) => {
|
|||||||
get: (key) => {
|
get: (key) => {
|
||||||
const fallback = fallbacks[key];
|
const fallback = fallbacks[key];
|
||||||
key = key.startsWith(namespace) ? key : namespace + key;
|
key = key.startsWith(namespace) ? key : namespace + key;
|
||||||
return select.get(key)?.value ?? fallback;
|
try {
|
||||||
|
return JSON.parse(select.get(key)?.value);
|
||||||
|
} catch {
|
||||||
|
return select.get(key)?.value ?? fallback;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
set: (key, value) => {
|
set: (key, value) => {
|
||||||
key = key.startsWith(namespace) ? key : namespace + key;
|
key = key.startsWith(namespace) ? key : namespace + key;
|
||||||
|
value = JSON.stringify(value);
|
||||||
return select.get(key) === undefined
|
return select.get(key) === undefined
|
||||||
? insert.run(key, value)
|
? insert.run(key, value)
|
||||||
: update.run(value, key);
|
: update.run(value, key);
|
||||||
|
@ -21,7 +21,7 @@ export default async (api, db) => {
|
|||||||
openMenuHotkey = await db.get("openMenuHotkey"),
|
openMenuHotkey = await db.get("openMenuHotkey"),
|
||||||
menuButtonIconStyle = await db.get("menuButtonIconStyle"),
|
menuButtonIconStyle = await db.get("menuButtonIconStyle"),
|
||||||
loadThemeOverrides = await db.get("loadThemeOverrides"),
|
loadThemeOverrides = await db.get("loadThemeOverrides"),
|
||||||
customStyles = JSON.parse((await db.get("customStyles")) || "{}").content;
|
customStyles = (await db.get("customStyles"))?.content;
|
||||||
|
|
||||||
// appearance
|
// appearance
|
||||||
|
|
||||||
@ -54,8 +54,8 @@ export default async (api, db) => {
|
|||||||
_notionTheme = notionTheme;
|
_notionTheme = notionTheme;
|
||||||
const msg = {
|
const msg = {
|
||||||
namespace: "notion-enhancer",
|
namespace: "notion-enhancer",
|
||||||
iconStyle: menuButtonIconStyle,
|
theme: notionTheme,
|
||||||
mode: notionTheme,
|
icon: menuButtonIconStyle,
|
||||||
};
|
};
|
||||||
$menuFrame?.contentWindow.postMessage(msg, "*");
|
$menuFrame?.contentWindow.postMessage(msg, "*");
|
||||||
}
|
}
|
||||||
@ -64,6 +64,7 @@ export default async (api, db) => {
|
|||||||
const openMenu = () => {
|
const openMenu = () => {
|
||||||
updateTheme(true);
|
updateTheme(true);
|
||||||
$menuModal?.setAttribute("open", true);
|
$menuModal?.setAttribute("open", true);
|
||||||
|
$menuFrame?.contentWindow.focus();
|
||||||
},
|
},
|
||||||
closeMenu = () => $menuModal?.removeAttribute("open");
|
closeMenu = () => $menuModal?.removeAttribute("open");
|
||||||
|
|
||||||
@ -129,6 +130,7 @@ export default async (api, db) => {
|
|||||||
});
|
});
|
||||||
document.querySelector(notionSidebar)?.append($menuButton);
|
document.querySelector(notionSidebar)?.append($menuButton);
|
||||||
|
|
||||||
|
window.addEventListener("focus", () => updateTheme(true));
|
||||||
addMutationListener("body", () => {
|
addMutationListener("body", () => {
|
||||||
if ($menuModal?.hasAttribute("open")) updateTheme();
|
if ($menuModal?.hasAttribute("open")) updateTheme();
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { setState, useState } from "./state.mjs";
|
import { setState, useState, getState } from "./state.mjs";
|
||||||
|
|
||||||
function Sidebar({}, ...children) {
|
function Sidebar({}, ...children) {
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi;
|
||||||
@ -43,7 +43,7 @@ function SidebarButton({ icon, ...props }, ...children) {
|
|||||||
<//>`;
|
<//>`;
|
||||||
if (!props.href) {
|
if (!props.href) {
|
||||||
const id = $el.innerText;
|
const id = $el.innerText;
|
||||||
$el.onclick ??= () => setState({ view: id });
|
$el.onclick ??= () => setState({ transition: "fade", view: id });
|
||||||
useState(["view"], ([view = "welcome"]) => {
|
useState(["view"], ([view = "welcome"]) => {
|
||||||
const active = view.toLowerCase() === id.toLowerCase();
|
const active = view.toLowerCase() === id.toLowerCase();
|
||||||
$el.style.background = active ? "var(--theme--bg-hover)" : "";
|
$el.style.background = active ? "var(--theme--bg-hover)" : "";
|
||||||
@ -55,16 +55,34 @@ function SidebarButton({ icon, ...props }, ...children) {
|
|||||||
|
|
||||||
function View({ id }, ...children) {
|
function View({ id }, ...children) {
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
|
duration = 100,
|
||||||
$el = html`<article
|
$el = html`<article
|
||||||
id=${id}
|
id=${id}
|
||||||
class="notion-enhancer--menu-view h-full
|
class="notion-enhancer--menu-view h-full
|
||||||
overflow-y-auto px-[60px] py-[36px] grow"
|
grow overflow-y-auto px-[60px] py-[36px]"
|
||||||
>
|
>
|
||||||
${children}
|
${children}
|
||||||
</article>`;
|
</article>`;
|
||||||
useState(["view"], ([view = "welcome"]) => {
|
useState(["view"], ([view = "welcome"]) => {
|
||||||
const active = view.toLowerCase() === id.toLowerCase();
|
const [transition] = getState(["transition"]),
|
||||||
$el.style.display = active ? "" : "none";
|
isVisible = $el.style.display !== "none",
|
||||||
|
nowActive = view.toLowerCase() === id.toLowerCase();
|
||||||
|
if (transition === "fade") {
|
||||||
|
$el.style.opacity = "0";
|
||||||
|
$el.style.transition = `opacity ${duration}ms`;
|
||||||
|
if (isVisible && !nowActive) {
|
||||||
|
setTimeout(() => ($el.style.display = "none"), duration);
|
||||||
|
} else if (!isVisible && nowActive) {
|
||||||
|
setTimeout(() => {
|
||||||
|
$el.style.display = "";
|
||||||
|
requestIdleCallback(() => ($el.style.opacity = "1"));
|
||||||
|
}, duration);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$el.style.transition = "";
|
||||||
|
$el.style.opacity = nowActive ? "1" : "0";
|
||||||
|
$el.style.display = nowActive ? "" : "none";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return $el;
|
return $el;
|
||||||
}
|
}
|
||||||
@ -83,11 +101,12 @@ function Mod({
|
|||||||
tags = [],
|
tags = [],
|
||||||
authors,
|
authors,
|
||||||
options = [],
|
options = [],
|
||||||
enabled,
|
_get,
|
||||||
_update,
|
_set,
|
||||||
_src,
|
_src,
|
||||||
}) {
|
}) {
|
||||||
const { html, enhancerUrl } = globalThis.__enhancerApi,
|
const { html, enhancerUrl } = globalThis.__enhancerApi,
|
||||||
|
toggleId = Math.random().toString(36).slice(2, 5),
|
||||||
$thumbnail = thumbnail
|
$thumbnail = thumbnail
|
||||||
? html`<img
|
? html`<img
|
||||||
src="${enhancerUrl(`${_src}/${thumbnail}`)}"
|
src="${enhancerUrl(`${_src}/${thumbnail}`)}"
|
||||||
@ -99,16 +118,13 @@ function Mod({
|
|||||||
class="flex items-center p-[4px] rounded-[4px] transition
|
class="flex items-center p-[4px] rounded-[4px] transition
|
||||||
text-[color:var(--theme--fg-secondary)] my-auto mr-[8px]
|
text-[color:var(--theme--fg-secondary)] my-auto mr-[8px]
|
||||||
duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
||||||
onclick=${() => {
|
onclick=${() => setState({ transition: "none", view: id })}
|
||||||
// open mod options page
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<i class="i-settings w-[18px] h-[18px]"></i>
|
<i class="i-settings w-[18px] h-[18px]"></i>
|
||||||
</button>`
|
</button>`
|
||||||
: "";
|
: "";
|
||||||
return html`<label
|
return html`<label
|
||||||
id=${id}
|
for=${toggleId}
|
||||||
for="${id}-toggle"
|
|
||||||
class="notion-enhancer--menu-mod flex items-stretch rounded-[4px]
|
class="notion-enhancer--menu-mod flex items-stretch rounded-[4px]
|
||||||
bg-[color:var(--theme--bg-secondary)] w-full py-[18px] px-[16px]
|
bg-[color:var(--theme--bg-secondary)] w-full py-[18px] px-[16px]
|
||||||
border border-[color:var(--theme--fg-border)] cursor-pointer
|
border border-[color:var(--theme--fg-border)] cursor-pointer
|
||||||
@ -133,7 +149,7 @@ function Mod({
|
|||||||
text-[color:var(--theme--fg-secondary)]"
|
text-[color:var(--theme--fg-secondary)]"
|
||||||
innerHTML=${description}
|
innerHTML=${description}
|
||||||
></p>
|
></p>
|
||||||
<div class="flex gap-x-[8px] text-[12px] leading-[16px]">
|
<div class="mt-auto flex gap-x-[8px] text-[12px] leading-[16px]">
|
||||||
${authors.map((author) => {
|
${authors.map((author) => {
|
||||||
return html`<a href=${author.homepage} class="flex items-center">
|
return html`<a href=${author.homepage} class="flex items-center">
|
||||||
<img src=${author.avatar} alt="" class="h-[12px] rounded-full" />
|
<img src=${author.avatar} alt="" class="h-[12px] rounded-full" />
|
||||||
@ -145,25 +161,20 @@ function Mod({
|
|||||||
<div class="flex ml-auto">
|
<div class="flex ml-auto">
|
||||||
${$options}
|
${$options}
|
||||||
<div class="my-auto scale-[1.15]">
|
<div class="my-auto scale-[1.15]">
|
||||||
<${Toggle}
|
<${Toggle} id=${toggleId} ...${{ _get, _set }} />
|
||||||
id="${id}-toggle"
|
|
||||||
checked=${enabled}
|
|
||||||
onchange="${(event) => _update(event.target.checked)}"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>`;
|
</label>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Option({ type, value, description, _update, ...props }) {
|
function Option({ type, value, description, _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
camelToSentenceCase = (string) =>
|
camelToSentenceCase = (string) =>
|
||||||
string[0].toUpperCase() +
|
string[0].toUpperCase() +
|
||||||
string.replace(/[A-Z]/g, (match) => ` ${match.toLowerCase()}`).slice(1);
|
string.replace(/[A-Z]/g, (match) => ` ${match.toLowerCase()}`).slice(1);
|
||||||
|
|
||||||
let $input;
|
let $input;
|
||||||
const label = props.label ?? camelToSentenceCase(props.key),
|
const label = props.label ?? camelToSentenceCase(props.key);
|
||||||
onchange = (event) => _update(event.target.value);
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "heading":
|
case "heading":
|
||||||
return html`<h4
|
return html`<h4
|
||||||
@ -174,40 +185,28 @@ function Option({ type, value, description, _update, ...props }) {
|
|||||||
${label}
|
${label}
|
||||||
</h4>`;
|
</h4>`;
|
||||||
case "text":
|
case "text":
|
||||||
$input = html`<${TextInput} ...${{ value, onchange }} />`;
|
$input = html`<${TextInput} ...${{ _get, _set }} />`;
|
||||||
break;
|
break;
|
||||||
case "number":
|
case "number":
|
||||||
$input = html`<${NumberInput} ...${{ value, onchange }} />`;
|
$input = html`<${NumberInput} ...${{ _get, _set }} />`;
|
||||||
break;
|
break;
|
||||||
case "hotkey":
|
case "hotkey":
|
||||||
$input = html`<${HotkeyInput} ...${{ value, onchange }} />`;
|
$input = html`<${HotkeyInput} ...${{ _get, _set }} />`;
|
||||||
break;
|
break;
|
||||||
case "color":
|
case "color":
|
||||||
$input = html`<${ColorInput} ...${{ value, onchange }} />`;
|
$input = html`<${ColorInput} ...${{ _get, _set }} />`;
|
||||||
break;
|
break;
|
||||||
case "file":
|
case "file":
|
||||||
try {
|
|
||||||
value = JSON.parse(value);
|
|
||||||
} catch {
|
|
||||||
value = {};
|
|
||||||
}
|
|
||||||
$input = html`<${FileInput}
|
$input = html`<${FileInput}
|
||||||
filename="${value.filename}"
|
|
||||||
extensions="${props.extensions}"
|
extensions="${props.extensions}"
|
||||||
onupload=${(upload) => _update(JSON.stringify(upload))}
|
...${{ _get, _set }}
|
||||||
/>`;
|
/>`;
|
||||||
break;
|
break;
|
||||||
case "select":
|
case "select":
|
||||||
$input = html`<${Select}
|
$input = html`<${Select} values=${props.values} ...${{ _get, _set }} />`;
|
||||||
values=${props.values}
|
|
||||||
...${{ value, onchange }}
|
|
||||||
/>`;
|
|
||||||
break;
|
break;
|
||||||
case "toggle":
|
case "toggle":
|
||||||
$input = html`<${Toggle}
|
$input = html`<${Toggle} ...${{ _get, _set }} />`;
|
||||||
checked=${value}
|
|
||||||
onchange=${(event) => _update(event.target.checked)}
|
|
||||||
/>`;
|
|
||||||
}
|
}
|
||||||
return html`<${type === "toggle" ? "label" : "div"}
|
return html`<${type === "toggle" ? "label" : "div"}
|
||||||
class="notion-enhancer--menu-option flex items-center justify-between
|
class="notion-enhancer--menu-option flex items-center justify-between
|
||||||
@ -225,19 +224,28 @@ function Option({ type, value, description, _update, ...props }) {
|
|||||||
<//>`;
|
<//>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextInput({ value, ...props }) {
|
function TextInput({ _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi,
|
||||||
return html`<label
|
$input = html`<input
|
||||||
class="notion-enhancer--menu-text-input
|
|
||||||
relative block w-full mt-[4px] mb-[8px]"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
type="text"
|
||||||
class="appearance-none text-[14px] leading-[1.2] rounded-[4px] pb-px
|
class="appearance-none text-[14px] leading-[1.2] rounded-[4px] pb-px
|
||||||
h-[28px] w-full pl-[8px] pr-[30px] bg-[color:var(--theme--bg-hover)]"
|
h-[28px] w-full pl-[8px] pr-[30px] bg-[color:var(--theme--bg-hover)]"
|
||||||
value=${value}
|
|
||||||
...${props}
|
...${props}
|
||||||
/>
|
/>`;
|
||||||
|
|
||||||
|
const { onchange } = $input;
|
||||||
|
$input.onchange = (event) => {
|
||||||
|
onchange?.(event);
|
||||||
|
_set?.($input.value);
|
||||||
|
};
|
||||||
|
useState(["rerender"], () => {
|
||||||
|
_get?.().then((value) => ($input.value = value));
|
||||||
|
});
|
||||||
|
|
||||||
|
return html`<label
|
||||||
|
class="notion-enhancer--menu-text-input
|
||||||
|
relative block w-full mt-[4px] mb-[8px]"
|
||||||
|
>${$input}
|
||||||
<i
|
<i
|
||||||
class="i-text-cursor pointer-events-none
|
class="i-text-cursor pointer-events-none
|
||||||
absolute right-[8px] top-[6px] w-[16px] h-[16px]
|
absolute right-[8px] top-[6px] w-[16px] h-[16px]
|
||||||
@ -246,19 +254,28 @@ function TextInput({ value, ...props }) {
|
|||||||
</label>`;
|
</label>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function NumberInput({ value, ...props }) {
|
function NumberInput({ _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi,
|
||||||
|
$input = html`<input
|
||||||
|
type="text"
|
||||||
|
class="appearance-none text-[14px] leading-[1.2] rounded-[4px] pb-px
|
||||||
|
h-[28px] w-full pl-[8px] pr-[32px] bg-[color:var(--theme--bg-hover)]"
|
||||||
|
...${props}
|
||||||
|
/>`;
|
||||||
|
|
||||||
|
const { onchange } = $input;
|
||||||
|
$input.onchange = (event) => {
|
||||||
|
onchange?.(event);
|
||||||
|
_set?.($input.value);
|
||||||
|
};
|
||||||
|
useState(["rerender"], () => {
|
||||||
|
_get?.().then((value) => ($input.value = value));
|
||||||
|
});
|
||||||
|
|
||||||
return html`<label
|
return html`<label
|
||||||
class="notion-enhancer--menu-number-input
|
class="notion-enhancer--menu-number-input
|
||||||
relative shrink-0 w-[192px]"
|
relative shrink-0 w-[192px]"
|
||||||
>
|
>${$input}
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
class="appearance-none text-[14px] leading-[1.2] rounded-[4px] pb-px
|
|
||||||
h-[28px] w-full pl-[8px] pr-[32px] bg-[color:var(--theme--bg-hover)]"
|
|
||||||
value=${value}
|
|
||||||
...${props}
|
|
||||||
/>
|
|
||||||
<i
|
<i
|
||||||
class="i-hash pointer-events-none
|
class="i-hash pointer-events-none
|
||||||
absolute right-[8px] top-[6px] w-[16px] h-[16px]
|
absolute right-[8px] top-[6px] w-[16px] h-[16px]
|
||||||
@ -267,8 +284,14 @@ function NumberInput({ value, ...props }) {
|
|||||||
</label>`;
|
</label>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function HotkeyInput({ value, onkeydown, ...props }) {
|
function HotkeyInput({ _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
|
$input = html`<input
|
||||||
|
type="text"
|
||||||
|
class="appearance-none text-[14px] leading-[1.2] rounded-[4px] pb-px
|
||||||
|
h-[28px] w-full pl-[8px] pr-[32px] bg-[color:var(--theme--bg-hover)]"
|
||||||
|
...${props}
|
||||||
|
/>`,
|
||||||
updateHotkey = (event) => {
|
updateHotkey = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const keys = [];
|
const keys = [];
|
||||||
@ -278,7 +301,7 @@ function HotkeyInput({ value, onkeydown, ...props }) {
|
|||||||
keys.push(alias);
|
keys.push(alias);
|
||||||
}
|
}
|
||||||
if (!keys.length && ["Backspace", "Delete"].includes(event.key)) {
|
if (!keys.length && ["Backspace", "Delete"].includes(event.key)) {
|
||||||
event.target.value = "";
|
$input.value = "";
|
||||||
} else if (event.key) {
|
} else if (event.key) {
|
||||||
let key = event.key;
|
let key = event.key;
|
||||||
if (key === " ") key = "Space";
|
if (key === " ") key = "Space";
|
||||||
@ -290,27 +313,26 @@ function HotkeyInput({ value, onkeydown, ...props }) {
|
|||||||
// avoid e.g. Shift+Shift, force inclusion of non-modifier
|
// avoid e.g. Shift+Shift, force inclusion of non-modifier
|
||||||
if (keys.includes(key)) return;
|
if (keys.includes(key)) return;
|
||||||
keys.push(key.length === 1 ? key.toUpperCase() : key);
|
keys.push(key.length === 1 ? key.toUpperCase() : key);
|
||||||
event.target.value = keys.join("+");
|
$input.value = keys.join("+");
|
||||||
}
|
}
|
||||||
event.target.dispatchEvent(new Event("input"));
|
$input.dispatchEvent(new Event("input"));
|
||||||
event.target.dispatchEvent(new Event("change"));
|
$input.dispatchEvent(new Event("change"));
|
||||||
};
|
};
|
||||||
props.onkeydown = (event) => {
|
|
||||||
|
const { onkeydown } = $input;
|
||||||
|
$input.onkeydown = (event) => {
|
||||||
updateHotkey(event);
|
updateHotkey(event);
|
||||||
onkeydown?.(event);
|
onkeydown?.(event);
|
||||||
|
_set?.($input.value);
|
||||||
};
|
};
|
||||||
|
useState(["rerender"], () => {
|
||||||
|
_get?.().then((value) => ($input.value = value));
|
||||||
|
});
|
||||||
|
|
||||||
return html`<label
|
return html`<label
|
||||||
class="notion-enhancer--menu-hotkey-input
|
class="notion-enhancer--menu-hotkey-input
|
||||||
relative shrink-0 w-[192px]"
|
relative shrink-0 w-[192px]"
|
||||||
>
|
>${$input}
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="appearance-none text-[14px] leading-[1.2] rounded-[4px] pb-px
|
|
||||||
h-[28px] w-full pl-[8px] pr-[32px] bg-[color:var(--theme--bg-hover)]"
|
|
||||||
value=${value}
|
|
||||||
...${props}
|
|
||||||
/>
|
|
||||||
<i
|
<i
|
||||||
class="i-command pointer-events-none
|
class="i-command pointer-events-none
|
||||||
absolute right-[8px] top-[6px] w-[16px] h-[16px]
|
absolute right-[8px] top-[6px] w-[16px] h-[16px]
|
||||||
@ -319,9 +341,21 @@ function HotkeyInput({ value, onkeydown, ...props }) {
|
|||||||
</label>`;
|
</label>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ColorInput({ value, ...props }) {
|
function ColorInput({ _get, _set, ...props }) {
|
||||||
|
Coloris({ format: "rgb" });
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
updateContrast = ($input, $icon) => {
|
$input = html`<input
|
||||||
|
type="text"
|
||||||
|
class="appearance-none text-[14px] leading-[1.2]
|
||||||
|
h-[28px] w-full pl-[8px] pr-[32px] pb-px"
|
||||||
|
data-coloris
|
||||||
|
...${props}
|
||||||
|
/>`,
|
||||||
|
$icon = html`<i
|
||||||
|
class="i-pipette pointer-events-none absolute opacity-70
|
||||||
|
right-[8px] top-[6px] w-[16px] h-[16px] text-current"
|
||||||
|
></i>`,
|
||||||
|
updateContrast = () => {
|
||||||
$input.style.background = $input.value;
|
$input.style.background = $input.value;
|
||||||
const [r, g, b, a = 1] = $input.value
|
const [r, g, b, a = 1] = $input.value
|
||||||
.replace(/^rgba?\(/, "")
|
.replace(/^rgba?\(/, "")
|
||||||
@ -337,26 +371,18 @@ function ColorInput({ value, ...props }) {
|
|||||||
$icon.style.color = $input.style.color;
|
$icon.style.color = $input.style.color;
|
||||||
};
|
};
|
||||||
|
|
||||||
const $input = html`<input
|
const { oninput } = $input;
|
||||||
type="text"
|
|
||||||
class="appearance-none text-[14px] leading-[1.2]
|
|
||||||
h-[28px] w-full pl-[8px] pr-[32px] pb-px"
|
|
||||||
style="background: ${value}"
|
|
||||||
value=${value}
|
|
||||||
data-coloris
|
|
||||||
...${props}
|
|
||||||
/>`,
|
|
||||||
$icon = html`<i
|
|
||||||
class="i-pipette pointer-events-none absolute opacity-70
|
|
||||||
right-[8px] top-[6px] w-[16px] h-[16px] text-current"
|
|
||||||
></i>`,
|
|
||||||
{ oninput } = $input;
|
|
||||||
$input.oninput = (event) => {
|
$input.oninput = (event) => {
|
||||||
oninput?.(event);
|
oninput?.(event);
|
||||||
updateContrast($input, $icon);
|
_set?.($input.value);
|
||||||
|
updateContrast();
|
||||||
};
|
};
|
||||||
updateContrast($input, $icon);
|
useState(["rerender"], () => {
|
||||||
Coloris({ format: "rgb" });
|
_get?.().then((value) => {
|
||||||
|
$input.value = value;
|
||||||
|
updateContrast();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return html`<label
|
return html`<label
|
||||||
class="notion-enhancer--menu-color-input shrink-0
|
class="notion-enhancer--menu-color-input shrink-0
|
||||||
@ -365,26 +391,27 @@ function ColorInput({ value, ...props }) {
|
|||||||
[position:0_0,4px_4px]
|
[position:0_0,4px_4px]
|
||||||
[size:8px_8px]
|
[size:8px_8px]
|
||||||
)"
|
)"
|
||||||
>
|
>${$input}${$icon}
|
||||||
${$input}${$icon}
|
|
||||||
</label>`;
|
</label>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function FileInput({ filename, extensions, onupload, onchange, ...props }) {
|
function FileInput({ extensions, _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
$filename = html`<span>${filename || "Upload a file"}</span>`,
|
$filename = html`<span>Upload a file</span>`,
|
||||||
$clear = html`<button
|
$clear = html`<button
|
||||||
class="ml-[8px] h-[14px] cursor-pointer text-[color:var(--theme--fg-secondary)]
|
class="ml-[8px] h-[14px] cursor-pointer text-[color:var(--theme--fg-secondary)]
|
||||||
transition duration-[20ms] hover:text-[color:var(--theme--fg-primary)]"
|
transition duration-[20ms] hover:text-[color:var(--theme--fg-primary)]"
|
||||||
style=${filename ? "" : "display: none"}
|
style="display: none"
|
||||||
onclick=${() => {
|
onclick=${() => {
|
||||||
$filename.innerText = "Upload a file";
|
$filename.innerText = "Upload a file";
|
||||||
$clear.style.display = "none";
|
$clear.style.display = "none";
|
||||||
onupload?.({ filename: "", content: "" });
|
_set?.({ filename: "", content: "" });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i class="i-x w-[14px] h-[14px]"></i>
|
<i class="i-x w-[14px] h-[14px]"></i>
|
||||||
</button>`;
|
</button>`;
|
||||||
|
|
||||||
|
const { onchange } = props;
|
||||||
props.onchange = (event) => {
|
props.onchange = (event) => {
|
||||||
const file = event.target.files[0],
|
const file = event.target.files[0],
|
||||||
reader = new FileReader();
|
reader = new FileReader();
|
||||||
@ -393,11 +420,18 @@ function FileInput({ filename, extensions, onupload, onchange, ...props }) {
|
|||||||
upload = { filename: file.name, content };
|
upload = { filename: file.name, content };
|
||||||
$filename.innerText = file.name;
|
$filename.innerText = file.name;
|
||||||
$clear.style.display = "";
|
$clear.style.display = "";
|
||||||
onupload?.(upload);
|
_set?.(upload);
|
||||||
};
|
};
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
onchange?.(event);
|
onchange?.(event);
|
||||||
};
|
};
|
||||||
|
useState(["rerender"], () => {
|
||||||
|
_get?.().then((file) => {
|
||||||
|
$filename.innerText = file?.filename || "Upload a file";
|
||||||
|
$clear.style.display = file?.filename ? "" : "none";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return html`<div
|
return html`<div
|
||||||
class="notion-enhancer--menu-file-input shrink-0 flex items-center"
|
class="notion-enhancer--menu-file-input shrink-0 flex items-center"
|
||||||
>
|
>
|
||||||
@ -423,9 +457,25 @@ function FileInput({ filename, extensions, onupload, onchange, ...props }) {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Select({ values, value, onchange, ...props }) {
|
function Select({ values, _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
updateWidth = ($select) => {
|
$select = html`<select
|
||||||
|
class="appearance-none bg-transparent rounded-[4px] cursor-pointer
|
||||||
|
text-[14px] leading-[1.2] pl-[8px] pr-[28px] h-[28px] max-w-[256px]
|
||||||
|
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
||||||
|
...${props}
|
||||||
|
>
|
||||||
|
${values.map((value) => {
|
||||||
|
return html`<option
|
||||||
|
value=${value}
|
||||||
|
class="bg-[color:var(--theme--bg-secondary)]
|
||||||
|
text-[color:var(--theme--fg-primary)]"
|
||||||
|
>
|
||||||
|
${value}
|
||||||
|
</option>`;
|
||||||
|
})}
|
||||||
|
</select>`,
|
||||||
|
updateWidth = () => {
|
||||||
const $tmp = html`<span
|
const $tmp = html`<span
|
||||||
class="text-[14px] pl-[8px] pr-[28px]
|
class="text-[14px] pl-[8px] pr-[28px]
|
||||||
absolute top-[-9999px] left-[-9999px]"
|
absolute top-[-9999px] left-[-9999px]"
|
||||||
@ -437,29 +487,19 @@ function Select({ values, value, onchange, ...props }) {
|
|||||||
$tmp.remove();
|
$tmp.remove();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
props.onchange = (event) => {
|
|
||||||
onchange?.(event);
|
|
||||||
updateWidth(event.target);
|
|
||||||
};
|
|
||||||
|
|
||||||
const $select = html`<select
|
const { onchange } = $select;
|
||||||
class="appearance-none bg-transparent rounded-[4px] cursor-pointer
|
$select.onchange = (event) => {
|
||||||
text-[14px] leading-[1.2] pl-[8px] pr-[28px] h-[28px] max-w-[256px]
|
onchange?.(event);
|
||||||
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
_set?.($select.value);
|
||||||
...${props}
|
updateWidth();
|
||||||
>
|
};
|
||||||
${values.map((value) => {
|
useState(["rerender"], () => {
|
||||||
return html`<option
|
_get?.().then((value) => {
|
||||||
value=${value}
|
$select.value = value;
|
||||||
class="bg-[color:var(--theme--bg-secondary)]
|
updateWidth();
|
||||||
text-[color:var(--theme--fg-primary)]"
|
});
|
||||||
>
|
});
|
||||||
${value}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>`;
|
|
||||||
$select.value = value ?? $select.value;
|
|
||||||
updateWidth($select);
|
|
||||||
|
|
||||||
return html`<div class="notion-enhancer--menu-select relative">
|
return html`<div class="notion-enhancer--menu-select relative">
|
||||||
${$select}
|
${$select}
|
||||||
@ -471,16 +511,27 @@ function Select({ values, value, onchange, ...props }) {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Toggle(props) {
|
function Toggle({ _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi,
|
||||||
return html`<div class="notion-enhancer--menu-toggle shrink-0">
|
$input = html`<input
|
||||||
<input
|
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="hidden checked:sibling:children:(
|
class="hidden checked:sibling:children:(
|
||||||
bg-[color:var(--theme--accent-primary)] after:translate-x-[12px])"
|
bg-[color:var(--theme--accent-primary)] after:translate-x-[12px])"
|
||||||
...${props}
|
...${props}
|
||||||
/>
|
/>`;
|
||||||
|
|
||||||
|
const { onchange } = $input;
|
||||||
|
$input.onchange = (event) => {
|
||||||
|
onchange?.(event);
|
||||||
|
_set?.($input.checked);
|
||||||
|
};
|
||||||
|
useState(["rerender"], () => {
|
||||||
|
_get?.().then((checked) => ($input.checked = checked));
|
||||||
|
});
|
||||||
|
|
||||||
|
return html`<div class="notion-enhancer--menu-toggle shrink-0">
|
||||||
|
${$input}
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="w-[30px] h-[18px] rounded-[44px] cursor-pointer
|
class="w-[30px] h-[18px] rounded-[44px] cursor-pointer
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { setState, useState } from "./state.mjs";
|
import { getState, setState, useState } from "./state.mjs";
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
SidebarSection,
|
SidebarSection,
|
||||||
@ -34,19 +34,16 @@ const renderOptions = async (mod) => {
|
|||||||
if (options[options.length - 1]?.type === "heading") options.pop();
|
if (options[options.length - 1]?.type === "heading") options.pop();
|
||||||
options = options.map(async (opt) => {
|
options = options.map(async (opt) => {
|
||||||
if (opt.type === "heading") return html`<${Option} ...${opt} />`;
|
if (opt.type === "heading") return html`<${Option} ...${opt} />`;
|
||||||
const value = await db.get(opt.key),
|
const _get = () => db.get(opt.key),
|
||||||
_update = (value) => db.set(opt.key, value);
|
_set = (value) => db.set(opt.key, value);
|
||||||
return html`<${Option} ...${{ ...opt, value, _update }} />`;
|
return html`<${Option} ...${{ ...opt, _get, _set }} />`;
|
||||||
});
|
});
|
||||||
return Promise.all(options);
|
return Promise.all(options);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderList = async (mods) => {
|
const compatibleMods = (mods) => {
|
||||||
const { html, platform, getProfile } = globalThis.__enhancerApi,
|
const { platform } = globalThis.__enhancerApi;
|
||||||
{ isEnabled, initDatabase } = globalThis.__enhancerApi,
|
return mods.filter((mod) => {
|
||||||
enabledMods = initDatabase([await getProfile(), "enabledMods"]);
|
|
||||||
mods = mods
|
|
||||||
.filter((mod) => {
|
|
||||||
const required =
|
const required =
|
||||||
mod.id &&
|
mod.id &&
|
||||||
mod.name &&
|
mod.name &&
|
||||||
@ -56,85 +53,123 @@ const renderList = async (mods) => {
|
|||||||
mod.authors,
|
mod.authors,
|
||||||
compatible = !mod.platforms || mod.platforms.includes(platform);
|
compatible = !mod.platforms || mod.platforms.includes(platform);
|
||||||
return required && compatible;
|
return required && compatible;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderList = async (mods) => {
|
||||||
|
const { html, getProfile, initDatabase } = globalThis.__enhancerApi,
|
||||||
|
enabledMods = initDatabase([await getProfile(), "enabledMods"]);
|
||||||
|
mods = compatibleMods(mods).map(async (mod) => {
|
||||||
|
const _get = () => enabledMods.get(mod.id),
|
||||||
|
_set = (enabled) => enabledMods.set(mod.id, enabled);
|
||||||
|
return html`<${Mod} ...${{ ...mod, _get, _set }} />`;
|
||||||
|
});
|
||||||
|
return html`<${List}>${await Promise.all(mods)}<//>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderOptionViews = async (parentView, mods) => {
|
||||||
|
const { html, getProfile, initDatabase } = globalThis.__enhancerApi,
|
||||||
|
enabledMods = initDatabase([await getProfile(), "enabledMods"]);
|
||||||
|
mods = compatibleMods(mods)
|
||||||
|
.filter((mod) => {
|
||||||
|
return mod.options?.filter((opt) => opt.type !== "heading").length;
|
||||||
})
|
})
|
||||||
.map(async (mod) => {
|
.map(async (mod) => {
|
||||||
const enabled = await isEnabled(mod.id),
|
const _get = () => enabledMods.get(mod.id),
|
||||||
_update = (enabled) => enabledMods.set(mod.id, enabled);
|
_set = (enabled) => enabledMods.set(mod.id, enabled);
|
||||||
return html`<${Mod} ...${{ ...mod, enabled, _update }} />`;
|
return html`<${View} id=${mod.id}>
|
||||||
|
<${Mod} ...${{ ...mod, options: [], _get, _set }} />
|
||||||
|
${await renderOptions(mod)}<//
|
||||||
|
>`;
|
||||||
});
|
});
|
||||||
return html`<${List}>${await Promise.all(mods)}<//>`;
|
return Promise.all(mods);
|
||||||
};
|
};
|
||||||
|
|
||||||
let renderStarted;
|
const render = async () => {
|
||||||
const render = async (iconStyle) => {
|
|
||||||
const { html, getCore, getThemes } = globalThis.__enhancerApi,
|
const { html, getCore, getThemes } = globalThis.__enhancerApi,
|
||||||
{ getExtensions, getIntegrations } = globalThis.__enhancerApi;
|
{ getExtensions, getIntegrations } = globalThis.__enhancerApi,
|
||||||
if (!html || !getCore || renderStarted) return;
|
[icon, renderStarted] = getState(["icon", "renderStarted"]);
|
||||||
renderStarted = true;
|
if (!html || !getCore || !icon || renderStarted) return;
|
||||||
|
setState({ renderStarted: true });
|
||||||
|
|
||||||
const $sidebar = html`<${Sidebar}>
|
const sidebar = [
|
||||||
${[
|
"notion-enhancer",
|
||||||
"notion-enhancer",
|
{
|
||||||
{
|
icon: `notion-enhancer${icon === "Monochrome" ? "?mask" : ""}`,
|
||||||
icon: `notion-enhancer${iconStyle === "Monochrome" ? "?mask" : ""}`,
|
title: "Welcome",
|
||||||
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" },
|
||||||
{ icon: "sliders-horizontal", title: "Core" },
|
{ icon: "palette", title: "Themes" },
|
||||||
{ icon: "palette", title: "Themes" },
|
{ icon: "zap", title: "Extensions" },
|
||||||
{ icon: "zap", title: "Extensions" },
|
{ icon: "plug", title: "Integrations" },
|
||||||
{ icon: "plug", title: "Integrations" },
|
],
|
||||||
].map((item) => {
|
$sidebar = html`<${Sidebar}>
|
||||||
if (typeof item === "string") {
|
${sidebar.map((item) => {
|
||||||
return html`<${SidebarSection}>${item}<//>`;
|
if (typeof item === "object") {
|
||||||
} else {
|
|
||||||
const { title, ...props } = item;
|
const { title, ...props } = item;
|
||||||
return html`<${SidebarButton} ...${props}>${title}<//>`;
|
return html`<${SidebarButton} ...${props}>${title}<//>`;
|
||||||
}
|
} else return html`<${SidebarSection}>${item}<//>`;
|
||||||
})}
|
})}
|
||||||
<//>`,
|
<//>`;
|
||||||
$views = [
|
document.body.append(
|
||||||
html`<${View} id="welcome">welcome<//>`,
|
$sidebar,
|
||||||
html`<${View} id="core">${await renderOptions(await getCore())}<//>`,
|
html`<${View} id="welcome">welcome<//>`,
|
||||||
html`<${View} id="themes">${await renderList(await getThemes())}<//>`,
|
html`<${View} id="core">${await renderOptions(await getCore())}<//>`
|
||||||
html`<${View} id="extensions">
|
);
|
||||||
${await renderList(await getExtensions())}
|
for (const { id, mods } of [
|
||||||
<//>`,
|
{ id: "themes", mods: await getThemes() },
|
||||||
html`<${View} id="integrations">
|
{ id: "extensions", mods: await getExtensions() },
|
||||||
${await renderList(await getIntegrations())}
|
{ id: "integrations", mods: await getIntegrations() },
|
||||||
<//>`,
|
]) {
|
||||||
];
|
document.body.append(
|
||||||
document.body.append($sidebar, ...$views);
|
html`<${View} id=${id}>${await renderList(mods)}<//>`,
|
||||||
|
...(await renderOptionViews(id, mods))
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("message", async (event) => {
|
window.addEventListener("focus", () => setState({ rerender: true }));
|
||||||
|
window.addEventListener("message", (event) => {
|
||||||
if (event.data?.namespace !== "notion-enhancer") return;
|
if (event.data?.namespace !== "notion-enhancer") return;
|
||||||
setState({ theme: event.data?.mode });
|
const [theme, icon] = getState(["theme", "icon"]);
|
||||||
|
setState({
|
||||||
|
rerender: true,
|
||||||
|
theme: event.data?.theme ?? theme,
|
||||||
|
icon: event.data?.icon ?? icon,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
useState(["theme"], ([theme]) => {
|
||||||
|
if (theme === "dark") document.body.classList.add("dark");
|
||||||
|
if (theme === "light") document.body.classList.remove("dark");
|
||||||
|
});
|
||||||
|
useState(["rerender"], async () => {
|
||||||
|
const [theme, icon] = getState(["theme", "icon"]);
|
||||||
|
if (!theme || !icon) return;
|
||||||
// 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
|
||||||
// ∴ notion-enhancer api is imported directly
|
// ∴ notion-enhancer api is imported directly
|
||||||
@ -148,9 +183,5 @@ window.addEventListener("message", async (event) => {
|
|||||||
// load stylesheets from enabled themes
|
// load stylesheets from enabled themes
|
||||||
await import("../../load.mjs");
|
await import("../../load.mjs");
|
||||||
// wait for api globals to be available
|
// wait for api globals to be available
|
||||||
requestIdleCallback(() => render(event.data?.iconStyle));
|
requestIdleCallback(() => render());
|
||||||
});
|
|
||||||
useState(["theme"], ([mode]) => {
|
|
||||||
if (mode === "dark") document.body.classList.add("dark");
|
|
||||||
if (mode === "light") document.body.classList.remove("dark");
|
|
||||||
});
|
});
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
const _state = {},
|
const _state = {},
|
||||||
_subscribers = [],
|
_subscribers = [],
|
||||||
|
getState = (keys) => {
|
||||||
|
return keys.map((key) => _state[key]);
|
||||||
|
},
|
||||||
setState = (state) => {
|
setState = (state) => {
|
||||||
Object.assign(_state, state);
|
Object.assign(_state, state);
|
||||||
const updates = Object.keys(state);
|
const updates = Object.keys(state);
|
||||||
@ -15,7 +18,7 @@ const _state = {},
|
|||||||
},
|
},
|
||||||
useState = (keys, callback) => {
|
useState = (keys, callback) => {
|
||||||
_subscribers.push([keys, callback]);
|
_subscribers.push([keys, callback]);
|
||||||
callback(keys.map((key) => _state[key]));
|
callback(getState(keys));
|
||||||
};
|
};
|
||||||
|
|
||||||
export { setState, useState };
|
export { setState, useState, getState };
|
||||||
|
@ -26,6 +26,12 @@
|
|||||||
"type": "heading",
|
"type": "heading",
|
||||||
"label": "Appearance"
|
"label": "Appearance"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "toggle",
|
||||||
|
"key": "toggle",
|
||||||
|
"description": "Sets whether the notion-enhancer icon added to Notion's sidebar should be coloured or monochrome. The latter style will match the theme's icon colour for users who would like the icon to be less noticeable.",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "select",
|
"type": "select",
|
||||||
"key": "menuButtonIconStyle",
|
"key": "menuButtonIconStyle",
|
||||||
@ -54,6 +60,18 @@
|
|||||||
"description": "Activates built-in debugging tools accessible through the application menu.",
|
"description": "Activates built-in debugging tools accessible through the application menu.",
|
||||||
"platforms": ["darwin", "win32", "linux"],
|
"platforms": ["darwin", "win32", "linux"],
|
||||||
"value": false
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"key": "text",
|
||||||
|
"description": "Activates built-in debugging tools accessible through the application menu.",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"key": "number",
|
||||||
|
"description": "Activates built-in debugging tools accessible through the application menu.",
|
||||||
|
"value": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"clientStyles": ["variables.css"],
|
"clientStyles": ["variables.css"],
|
||||||
|
@ -12,5 +12,50 @@
|
|||||||
"avatar": "https://dragonwocky.me/avatar.jpg"
|
"avatar": "https://dragonwocky.me/avatar.jpg"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"label": "Hotkeys"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hotkey",
|
||||||
|
"key": "openMenuHotkey",
|
||||||
|
"description": "Opens the notion-enhancer menu from within Notion.",
|
||||||
|
"value": "Ctrl+Shift+,"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"label": "Appearance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"key": "menuButtonIconStyle",
|
||||||
|
"description": "Sets whether the notion-enhancer icon added to Notion's sidebar should be coloured or monochrome. The latter style will match the theme's icon colour for users who would like the icon to be less noticeable.",
|
||||||
|
"values": ["Colour", "Monochrome"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"key": "loadThemeOverrides",
|
||||||
|
"description": "Loads the styling required for a theme to customise Notion's interface. Disabling this will increase client performance.",
|
||||||
|
"values": ["Auto", "Enabled", "Disabled"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"key": "customStyles",
|
||||||
|
"description": "Adds the styles from an uploaded .css file to Notion. Use this if you would like to customise the current theme or <a href=\"https://notion-enhancer.github.io/advanced/tweaks\">otherwise tweak Notion's appearance</a>.",
|
||||||
|
"extensions": ["css"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"label": "Advanced"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "toggle",
|
||||||
|
"key": "debugMode",
|
||||||
|
"description": "Activates built-in debugging tools accessible through the application menu.",
|
||||||
|
"platforms": ["darwin", "win32", "linux"],
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
],
|
||||||
"clientStyles": ["client.css"]
|
"clientStyles": ["client.css"]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user