From 530be53e7090aa7bedc63a1914320b589ce75966 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Sun, 15 Jan 2023 22:54:57 +1100 Subject: [PATCH] feat(menu): add searchbar + descriptions to mod lists, fix(menu): natural keyboard interactions w/ `, $icon = html``; useState(["rerender"], () => onrerender?.($input, $icon)); return html``; } @@ -255,7 +295,7 @@ function Input({ wide, transparent, icon, onrerender, ...props }) { function TextInput({ _get, _set, onchange, ...props }) { const { html } = globalThis.__enhancerApi; return html`<${Input} - wide + size="md" type="text" icon="text-cursor" onchange=${(event) => { @@ -272,6 +312,7 @@ function TextInput({ _get, _set, onchange, ...props }) { function NumberInput({ _get, _set, onchange, ...props }) { const { html } = globalThis.__enhancerApi; return html`<${Input} + size="sm" type="number" icon="hash" onchange=${(event) => { @@ -314,6 +355,7 @@ function HotkeyInput({ _get, _set, onkeydown, ...props }) { event.target.dispatchEvent(new Event("change")); }; return html`<${Input} + size="sm" type="text" icon="command" onkeydown=${(event) => { @@ -349,6 +391,7 @@ function ColorInput({ _get, _set, oninput, ...props }) { }; return html`<${Input} transparent + size="sm" type="text" icon="pipette" data-coloris @@ -439,6 +482,9 @@ function Select({ values, _get, _set, ...props }) { transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]" ...${props} >`, + $options = values.map((value) => { + return html`<${SelectOption} ...${{ value, _get, _set }} />`; + }), $popup = html`
- ${values.map((value) => { - return html`<${SelectOption} ...${{ value, _get, _set }} />`; - })} + ${$options}
`; - const { onclick } = $select; + const { onclick, onkeydown } = $select, + openPopup = () => { + $popup.setAttribute("open", true); + $options.forEach(($opt) => ($opt.tabIndex = 0)); + setState({ popupOpen: true }); + }, + closePopup = (value) => { + $popup.removeAttribute("open"); + $options.forEach(($opt) => ($opt.tabIndex = -1)); + $select.style.width = `${$select.offsetWidth}px`; + $select.style.background = "transparent"; + if (value) $select.innerText = value; + setTimeout(() => { + $select.style.width = ""; + $select.style.background = ""; + setState({ popupOpen: false }); + }, 200); + }; $select.onclick = (event) => { onclick?.(event); - $popup.setAttribute("open", true); - setState({ popupOpen: true }); + openPopup(); + }; + $select.onkeydown = (event) => { + onkeydown?.(event); + if (event.key === "Enter") openPopup(); }; useState(["rerender"], () => { _get?.().then((value) => { if ($popup.hasAttribute("open")) { - $popup.removeAttribute("open"); - $select.style.width = `${$select.offsetWidth}px`; - $select.style.background = "transparent"; - $select.innerText = value; - setTimeout(() => { - $select.style.width = ""; - $select.style.background = ""; - setState({ popupOpen: false }); - }, 200); + closePopup(value); } else $select.innerText = value; }); }); document.addEventListener("click", (event) => { if (!$popup.hasAttribute("open")) return; if ($popup.contains(event.target) || event.target === $select) return; - _set?.($select.innerText); + closePopup(); }); return html`
@@ -501,7 +557,6 @@ function SelectOption({ value, _get, _set, ...props }) { $selected = html``, $option = html`
`; - const { onclick } = $option; + const { onclick, onkeydown } = $option; $option.onclick = (event) => { onclick?.(event); _set?.(value); }; + $option.onkeydown = (event) => { + onkeydown?.(event); + if (event.key === "Enter") _set?.(value); + }; useState(["rerender"], () => { _get?.().then((actualValue) => { if (actualValue === value) { diff --git a/src/core/menu/menu.mjs b/src/core/menu/menu.mjs index 5b6c052..20933d7 100644 --- a/src/core/menu/menu.mjs +++ b/src/core/menu/menu.mjs @@ -58,7 +58,7 @@ const compatibleMods = (mods) => { return required && compatible; }); }, - renderList = async (mods) => { + renderList = async (mods, description) => { const { html, getProfile, initDatabase } = globalThis.__enhancerApi, enabledMods = initDatabase([await getProfile(), "enabledMods"]); mods = compatibleMods(mods).map(async (mod) => { @@ -69,30 +69,31 @@ const compatibleMods = (mods) => { }; return html`<${Mod} ...${{ ...mod, _get, _set }} />`; }); - return html`<${List}>${await Promise.all(mods)}`; + return html`<${List} description=${description}> + ${await Promise.all(mods)} + `; + }, + 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) => { + const _get = () => enabledMods.get(mod.id), + _set = async (enabled) => { + await enabledMods.set(mod.id, enabled); + setState({ rerender: true }); + }; + return html`<${View} id=${mod.id}> + <${Mod} ...${{ ...mod, options: [], _get, _set }} /> + ${await renderOptions(mod)}`; + }); + return 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) => { - const _get = () => enabledMods.get(mod.id), - _set = async (enabled) => { - await enabledMods.set(mod.id, enabled); - setState({ rerender: true }); - }; - return html`<${View} id=${mod.id}> - <${Mod} ...${{ ...mod, options: [], _get, _set }} /> - ${await renderOptions(mod)}`; - }); - return Promise.all(mods); -}; - const render = async () => { const { html, getCore, getThemes } = globalThis.__enhancerApi, { getExtensions, getIntegrations } = globalThis.__enhancerApi, @@ -150,13 +151,32 @@ const render = async () => { html`<${View} id="welcome">welcome`, html`<${View} id="core">${await renderOptions(await getCore())}` ); - for (const { id, mods } of [ - { id: "themes", mods: await getThemes() }, - { id: "extensions", mods: await getExtensions() }, - { id: "integrations", mods: await getIntegrations() }, + for (const { id, mods, description } of [ + { + id: "themes", + mods: await getThemes(), + description: `Themes override Notion's colour schemes. To switch between + dark mode and light mode, go to Settings & members → My notifications & + settings → My settings → Appearance.`, + }, + { + id: "extensions", + mods: await getExtensions(), + description: `Extensions add to the functionality and layout of the Notion + client, interacting with and modifying existing interfaces.`, + }, + { + id: "integrations", + mods: await getIntegrations(), + description: ` + Integrations access and modify Notion content. They interact directly with + + https://www.notion.so/api/v3. Use at your own risk.`, + }, ]) { document.body.append( - html`<${View} id=${id}>${await renderList(mods)}`, + html`<${View} id=${id}>${await renderList(mods, description)}`, ...(await renderOptionViews(id, mods)) ); }