feat(menu): display profile upload status as popup

This commit is contained in:
dragonwocky 2023-01-23 23:43:04 +11:00
parent e3f34dfc21
commit 7b6a244d72
Signed by: dragonwocky
GPG Key ID: 7998D08F7D7BD7A8
2 changed files with 50 additions and 28 deletions

View File

@ -46,21 +46,23 @@ function Popup({ trigger, onopen, onclose, onbeforeclose }, ...children) {
}; };
$popup.querySelectorAll("[tabindex]").forEach(($el) => ($el.tabIndex = -1)); $popup.querySelectorAll("[tabindex]").forEach(($el) => ($el.tabIndex = -1));
extendProps(trigger, { if (trigger) {
onclick: $popup.show, extendProps(trigger, {
onkeydown(event) { onclick: $popup.show,
if (event.key === "Enter") $popup.show(); onkeydown(event) {
}, if (event.key === "Enter") $popup.show();
}); },
useState(["rerender"], () => { });
if ($popup.hasAttribute("open")) $popup.hide(); }
});
document.addEventListener("click", (event) => { document.addEventListener("click", (event) => {
if (!$popup.hasAttribute("open")) return; if (!$popup.hasAttribute("open")) return;
if ($popup.contains(event.target) || $popup === event.target) return; if ($popup.contains(event.target) || $popup === event.target) return;
if (trigger.contains(event.target) || trigger === event.target) return; if (trigger?.contains(event.target) || trigger === event.target) return;
$popup.hide(); $popup.hide();
}); });
useState(["rerender"], () => {
if ($popup.hasAttribute("open")) $popup.hide();
});
return $popup; return $popup;
} }

View File

@ -24,17 +24,37 @@ function Profile({ id }) {
}, },
setName = async (name) => { setName = async (name) => {
// name only has effect in menu // name only has effect in menu
// doesn't need reload triggered // doesn't need to trigger reload
await profile.set("profileName", name); await profile.set("profileName", name);
}; },
isActive = async () => {
const isActive = async () => id === (await getProfile()), return id === (await getProfile());
},
setActive = async () => { setActive = async () => {
await db.set("activeProfile", id); await db.set("activeProfile", id);
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true, databaseUpdated: true });
}; };
const uploadProfile = (event) => { const $successName = html`<span
class="py-[2px] px-[4px] rounded-[3px]
bg-[color:var(--theme--bg-hover)]"
></span>`,
$success = html`<${Popup}
onopen=${async () => ($successName.innerText = await getName())}
>
<p class="py-[2px] px-[8px] text-[14px]">
The profile ${$successName} has been updated successfully.
</p>
<//>`,
$error = html`<${Popup}>
<p
class="py-[2px] px-[8px] text-[14px]
text-[color:var(--theme--accent-secondary)]"
>
An error was encountered attempting to parse the uploaded file.
</p>
<//>`,
uploadProfile = (event) => {
const file = event.target.files[0], const file = event.target.files[0],
reader = new FileReader(); reader = new FileReader();
reader.onload = async (progress) => { reader.onload = async (progress) => {
@ -45,8 +65,11 @@ function Profile({ id }) {
profileName: await getName(), profileName: await getName(),
}); });
setState({ rerender: true, databaseUpdated: true }); setState({ rerender: true, databaseUpdated: true });
$success.show();
setTimeout(() => $success.hide(), 2000);
} catch (err) { } catch (err) {
console.error(err); $error.show();
setTimeout(() => $error.hide(), 2000);
} }
}; };
reader.readAsText(file); reader.readAsText(file);
@ -87,25 +110,22 @@ function Profile({ id }) {
} else setState({ rerender: true }); } else setState({ rerender: true });
}; };
const $name = html`<span const $delete = html`<button
class="py-[2px] px-[4px] rounded-[3px]
bg-[color:var(--theme--bg-hover)]"
></span>`,
$delete = html`<button
class="h-[14px] transition duration-[20ms] class="h-[14px] transition duration-[20ms]
text-[color:var(--theme--fg-secondary)] text-[color:var(--theme--fg-secondary)]
hover:text-[color:var(--theme--fg-primary)]" hover:text-[color:var(--theme--fg-primary)]"
> >
<i class="i-x w-[14px] h-[14px]"></i> <i class="i-x w-[14px] h-[14px]"></i>
</button>`, </button>`,
$confirmName = $successName.cloneNode(true),
$confirm = html`<${Popup} $confirm = html`<${Popup}
trigger=${$delete} trigger=${$delete}
onopen=${async () => ($name.innerText = await getName())} onopen=${async () => ($confirmName.innerText = await getName())}
> >
<p class="text-[14px] pt-[2px] px-[8px]"> <p class="text-[14px] py-[2px] px-[8px]">
Are you sure you want to delete the profile ${$name} permanently? Are you sure you want to delete the profile ${$confirmName} permanently?
</p> </p>
<div class="flex flex-col gap-[8px] p-[8px]"> <div class="flex flex-col gap-[8px] py-[6px] px-[8px]">
<${Button} <${Button}
tabindex="0" tabindex="0"
icon="trash" icon="trash"
@ -131,16 +151,16 @@ function Profile({ id }) {
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 }} />
<${Button} size="sm" icon="import" tagName="label"> <${Button} variant="sm" icon="import" class="relative" tagName="label">
<input <input
type="file" type="file"
class="hidden" class="hidden"
accept=".json" accept=".json"
onchange=${uploadProfile} onchange=${uploadProfile}
/> />
Import Import ${$success} ${$error}
<//> <//>
<${Button} size="sm" icon="upload" onclick=${downloadProfile}>Export<//> <${Button} variant="sm" icon="upload" onclick=${downloadProfile}>Export<//>
<div class="relative flex">${$delete}${$confirm}</div> <div class="relative flex">${$delete}${$confirm}</div>
</li>`; </li>`;
} }