mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-08 06:29:03 +00:00
feat(menu): mimic notion select options popup
electron was positioning options distanced from their <select> for... some reason
This commit is contained in:
parent
d1f83884aa
commit
e681d462d3
@ -71,13 +71,11 @@ export default async (api, db) => {
|
|||||||
$menuFrame = html`<iframe
|
$menuFrame = html`<iframe
|
||||||
title="notion-enhancer menu"
|
title="notion-enhancer menu"
|
||||||
src="${enhancerUrl("core/menu/index.html")}"
|
src="${enhancerUrl("core/menu/index.html")}"
|
||||||
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-primary)] 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=${() => {
|
onload=${() => {
|
||||||
// pass notion-enhancer api to electron menu process
|
// pass notion-enhancer api to electron menu process
|
||||||
if (platform !== "browser") {
|
if (platform !== "browser") {
|
||||||
|
@ -400,7 +400,7 @@ function FileInput({ extensions, _get, _set, ...props }) {
|
|||||||
$filename = html`<span>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)] flex"
|
||||||
style="display: none"
|
style="display: none"
|
||||||
onclick=${() => {
|
onclick=${() => {
|
||||||
$filename.innerText = "Upload a file";
|
$filename.innerText = "Upload a file";
|
||||||
@ -459,50 +459,57 @@ function FileInput({ extensions, _get, _set, ...props }) {
|
|||||||
|
|
||||||
function Select({ values, _get, _set, ...props }) {
|
function Select({ values, _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
$select = html`<select
|
$select = html`<div
|
||||||
|
dir="rtl"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
class="appearance-none bg-transparent rounded-[4px] cursor-pointer
|
class="appearance-none bg-transparent rounded-[4px] cursor-pointer
|
||||||
text-[14px] leading-[1.2] pl-[8px] pr-[28px] h-[28px] max-w-[256px]
|
text-[14px] leading-[28px] h-[28px] max-w-[256px] pl-[8px] pr-[28px]
|
||||||
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
||||||
...${props}
|
...${props}
|
||||||
|
></div>`,
|
||||||
|
$popup = html`<div
|
||||||
|
class="group absolute top-0 left-0
|
||||||
|
flex flex-col justify-center items-end
|
||||||
|
pointer-events-none w-full h-full"
|
||||||
>
|
>
|
||||||
${values.map((value) => {
|
<div class="relative right-[100%]">
|
||||||
return html`<option
|
<div
|
||||||
value=${value}
|
|
||||||
class="bg-[color:var(--theme--bg-secondary)]
|
class="bg-[color:var(--theme--bg-secondary)]
|
||||||
text-[color:var(--theme--fg-primary)]"
|
w-[250px] max-w-[calc(100vw-24px)] max-h-[70vh]
|
||||||
|
py-[6px] px-[4px] drop-shadow-xl overflow-y-auto
|
||||||
|
transition duration-[200ms] opacity-0 scale-95 rounded-[4px]
|
||||||
|
group-open:(pointer-events-auto opacity-100 scale-100)"
|
||||||
>
|
>
|
||||||
${value}
|
${values.map((value) => {
|
||||||
</option>`;
|
return html`<${SelectOption} ...${{ value, _get, _set }} />`;
|
||||||
})}
|
})}
|
||||||
</select>`,
|
</div>
|
||||||
updateWidth = () => {
|
</div>
|
||||||
const $tmp = html`<span
|
</div>`;
|
||||||
class="text-[14px] pl-[8px] pr-[28px]
|
|
||||||
absolute top-[-9999px] left-[-9999px]"
|
|
||||||
>${$select.value}</span
|
|
||||||
>`;
|
|
||||||
document.body.append($tmp);
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
$select.style.width = `${Math.min($tmp.offsetWidth, 256)}px`;
|
|
||||||
$tmp.remove();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const { onchange } = $select;
|
const { onclick } = $select;
|
||||||
$select.onchange = (event) => {
|
$select.onclick = (event) => {
|
||||||
onchange?.(event);
|
onclick?.(event);
|
||||||
_set?.($select.value);
|
$popup.setAttribute("open", true);
|
||||||
updateWidth();
|
|
||||||
};
|
};
|
||||||
useState(["rerender"], () => {
|
useState(["rerender"], () => {
|
||||||
_get?.().then((value) => {
|
_get?.().then((value) => {
|
||||||
$select.value = value;
|
if ($popup.hasAttribute("open")) {
|
||||||
updateWidth();
|
$popup.removeAttribute("open");
|
||||||
|
$select.style.width = `${$select.offsetWidth}px`;
|
||||||
|
$select.style.background = "transparent";
|
||||||
|
$select.innerText = value;
|
||||||
|
setTimeout(() => {
|
||||||
|
$select.style.width = "";
|
||||||
|
$select.style.background = "";
|
||||||
|
}, 200);
|
||||||
|
} else $select.innerText = value;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return html`<div class="notion-enhancer--menu-select relative">
|
return html`<div class="notion-enhancer--menu-select relative">
|
||||||
${$select}
|
${$select}${$popup}
|
||||||
<i
|
<i
|
||||||
class="i-chevron-down pointer-events-none
|
class="i-chevron-down pointer-events-none
|
||||||
absolute right-[6px] top-[6px] w-[16px] h-[16px]
|
absolute right-[6px] top-[6px] w-[16px] h-[16px]
|
||||||
@ -511,13 +518,45 @@ function Select({ values, _get, _set, ...props }) {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SelectOption({ value, _get, _set, ...props }) {
|
||||||
|
const { html } = globalThis.__enhancerApi,
|
||||||
|
$selected = html`<i class="ml-auto i-check w-[16px] h-[16px]"></i>`,
|
||||||
|
$option = html`<div
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
class="select-none cursor-pointer rounded-[3px]
|
||||||
|
flex items-center w-full h-[28px] px-[12px] leading-[1.2]
|
||||||
|
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
||||||
|
...${props}
|
||||||
|
>
|
||||||
|
<div class="mr-[6px] text-[14px] text-ellipsis overflow-hidden">
|
||||||
|
${value}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
const { onclick } = $option;
|
||||||
|
$option.onclick = (event) => {
|
||||||
|
onclick?.(event);
|
||||||
|
_set?.(value);
|
||||||
|
};
|
||||||
|
useState(["rerender"], () => {
|
||||||
|
_get?.().then((actualValue) => {
|
||||||
|
if (actualValue === value) {
|
||||||
|
$option.append($selected);
|
||||||
|
} else $selected.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return $option;
|
||||||
|
}
|
||||||
|
|
||||||
function Toggle({ _get, _set, ...props }) {
|
function Toggle({ _get, _set, ...props }) {
|
||||||
const { html } = globalThis.__enhancerApi,
|
const { html } = globalThis.__enhancerApi,
|
||||||
$input = html`<input
|
$input = html`<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}
|
||||||
/>`;
|
/>`;
|
||||||
|
|
||||||
|
@ -35,7 +35,10 @@ const renderOptions = async (mod) => {
|
|||||||
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 _get = () => db.get(opt.key),
|
const _get = () => db.get(opt.key),
|
||||||
_set = (value) => db.set(opt.key, value);
|
_set = async (value) => {
|
||||||
|
await db.set(opt.key, value);
|
||||||
|
setState({ rerender: true });
|
||||||
|
};
|
||||||
return html`<${Option} ...${{ ...opt, _get, _set }} />`;
|
return html`<${Option} ...${{ ...opt, _get, _set }} />`;
|
||||||
});
|
});
|
||||||
return Promise.all(options);
|
return Promise.all(options);
|
||||||
@ -60,7 +63,10 @@ const compatibleMods = (mods) => {
|
|||||||
enabledMods = initDatabase([await getProfile(), "enabledMods"]);
|
enabledMods = initDatabase([await getProfile(), "enabledMods"]);
|
||||||
mods = compatibleMods(mods).map(async (mod) => {
|
mods = compatibleMods(mods).map(async (mod) => {
|
||||||
const _get = () => enabledMods.get(mod.id),
|
const _get = () => enabledMods.get(mod.id),
|
||||||
_set = (enabled) => enabledMods.set(mod.id, enabled);
|
_set = async (enabled) => {
|
||||||
|
await enabledMods.set(mod.id, enabled);
|
||||||
|
setState({ rerender: true });
|
||||||
|
};
|
||||||
return html`<${Mod} ...${{ ...mod, _get, _set }} />`;
|
return html`<${Mod} ...${{ ...mod, _get, _set }} />`;
|
||||||
});
|
});
|
||||||
return html`<${List}>${await Promise.all(mods)}<//>`;
|
return html`<${List}>${await Promise.all(mods)}<//>`;
|
||||||
@ -75,7 +81,10 @@ const renderOptionViews = async (parentView, mods) => {
|
|||||||
})
|
})
|
||||||
.map(async (mod) => {
|
.map(async (mod) => {
|
||||||
const _get = () => enabledMods.get(mod.id),
|
const _get = () => enabledMods.get(mod.id),
|
||||||
_set = (enabled) => enabledMods.set(mod.id, enabled);
|
_set = async (enabled) => {
|
||||||
|
await enabledMods.set(mod.id, enabled);
|
||||||
|
setState({ rerender: true });
|
||||||
|
};
|
||||||
return html`<${View} id=${mod.id}>
|
return html`<${View} id=${mod.id}>
|
||||||
<${Mod} ...${{ ...mod, options: [], _get, _set }} />
|
<${Mod} ...${{ ...mod, options: [], _get, _set }} />
|
||||||
${await renderOptions(mod)}<//
|
${await renderOptions(mod)}<//
|
||||||
|
Loading…
Reference in New Issue
Block a user