mirror of
https://github.com/nekename/OpenDeck.git
synced 2026-10-28 09:44:01 +00:00
feat: add dialog semantics and accessible labels to popups and the plugin manager (#294)
Co-authored-by: nekename <63245705+nekename@users.noreply.github.com>
This commit is contained in:
1 parent
37648f8636
commit
758214d92e
7 files changed
+45
-16
No files matched your search
@@ -117,7 +117,7 @@
|
||||
role="option"
|
||||
aria-selected="false"
|
||||
tabindex={i == 0 ? 0 : -1}
|
||||
aria-label="{$localisations?.[action.plugin]?.[action.uuid]?.Name ?? action.name}: {$localisations?.[action.plugin]?.[action.uuid]?.Tooltip ?? action.tooltip}"
|
||||
aria-label={$localisations?.[action.plugin]?.[action.uuid]?.Name ?? action.name}
|
||||
on:dragstart={(event) => {
|
||||
if (!event.dataTransfer) return;
|
||||
event.dataTransfer.effectAllowed = "copy";
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
export let hidden: boolean = false;
|
||||
export let disconnected: boolean = false;
|
||||
export let action: () => void;
|
||||
export let actionLabel: string = "";
|
||||
export let secondaryAction: (() => void) | undefined = undefined;
|
||||
export let secondaryActionLabel: string = "";
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -20,11 +22,11 @@
|
||||
|
||||
<div class="flex flex-col ml-auto mr-4">
|
||||
{#if secondaryAction}
|
||||
<button on:click={secondaryAction}>
|
||||
<button on:click={secondaryAction} aria-label={secondaryActionLabel}>
|
||||
<slot name="secondary" />
|
||||
</button>
|
||||
{/if}
|
||||
<button on:click={action}>
|
||||
<button on:click={action} aria-label={actionLabel}>
|
||||
<slot />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<Popup show>
|
||||
<button class="mr-2 my-1 float-right text-xl text-neutral-300" on:click={close}>✕</button>
|
||||
<Popup show label="{details.name} plugin details">
|
||||
<button class="mr-2 my-1 float-right text-xl text-neutral-300" on:click={close} aria-label="Close">✕</button>
|
||||
<div class="flex flex-row items-start">
|
||||
<img
|
||||
src={"https://openactionapi.github.io/plugins/icons/" + id + ".png"}
|
||||
@@ -111,6 +111,7 @@
|
||||
<button
|
||||
on:click={() => invoke("open_url", { url: details.download_url ?? details.repository + "/releases/latest" })}
|
||||
class="ml-1 p-3.5 active:translate-y-0.5 text-lg text-neutral-100 bg-indigo-600 hover:bg-indigo-500 transition-colors border border-indigo-500 rounded-r-lg"
|
||||
aria-label="Download latest release from GitHub"
|
||||
>
|
||||
<ArrowSquareOut size={24} />
|
||||
</button>
|
||||
|
||||
@@ -212,8 +212,8 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<Popup show={showPopup}>
|
||||
<button class="mr-2 my-1 float-right text-xl text-neutral-300" on:click={() => showPopup = false}>✕</button>
|
||||
<Popup show={showPopup} label="Manage plugins">
|
||||
<button class="mr-2 my-1 float-right text-xl text-neutral-300" on:click={() => showPopup = false} aria-label="Close">✕</button>
|
||||
<h2 class="m-2 font-semibold text-xl text-neutral-300">Manage plugins</h2>
|
||||
|
||||
<h2 class="mx-2 mt-6 mb-2 text-lg text-neutral-400">Installed plugins</h2>
|
||||
@@ -235,10 +235,9 @@
|
||||
if ($settings?.developer) invoke("reload_plugin", { id: plugin.id });
|
||||
else removePlugin(plugin);
|
||||
}}
|
||||
secondaryAction={() => {
|
||||
if (!plugin.registered) invoke("open_log_directory");
|
||||
else if (plugin.has_settings_interface) invoke("show_settings_interface", { plugin: plugin.id });
|
||||
}}
|
||||
actionLabel={$settings?.developer ? "Reload" : "Remove"}
|
||||
secondaryAction={!plugin.registered ? () => invoke("open_log_directory") : plugin.has_settings_interface ? () => invoke("show_settings_interface", { plugin: plugin.id }) : undefined}
|
||||
secondaryActionLabel={!plugin.registered ? "View logs" : "Settings"}
|
||||
>
|
||||
<svelte:fragment slot="subtitle">
|
||||
{plugin.version}
|
||||
@@ -295,6 +294,7 @@
|
||||
bind:value={query}
|
||||
class="w-full p-2 text-neutral-300"
|
||||
placeholder="Search plugins"
|
||||
aria-label="Search plugins"
|
||||
type="search"
|
||||
spellcheck="false"
|
||||
/>
|
||||
@@ -315,6 +315,7 @@
|
||||
subtitle={plugin.author}
|
||||
hidden={!plugin.name.toLowerCase().includes(query.toLowerCase())}
|
||||
action={() => openDetailsView = id}
|
||||
actionLabel="View details"
|
||||
>
|
||||
<ArrowSquareOut size="24" class="text-neutral-400" />
|
||||
</ListedPlugin>
|
||||
@@ -347,6 +348,7 @@
|
||||
subtitle={plugin.author}
|
||||
hidden={!plugin.name.toLowerCase().includes(query.toLowerCase())}
|
||||
action={() => installPluginElgato(plugin)}
|
||||
actionLabel="Install"
|
||||
>
|
||||
<CloudArrowDown size="24" class="text-neutral-400" />
|
||||
</ListedPlugin>
|
||||
@@ -372,7 +374,9 @@
|
||||
download_url: undefined,
|
||||
});
|
||||
}}
|
||||
actionLabel="Install"
|
||||
secondaryAction={() => window.open("https://tacto.live")}
|
||||
secondaryActionLabel="Visit website"
|
||||
>
|
||||
<svelte:fragment slot="secondary">
|
||||
<ArrowSquareOut size="24" class="text-neutral-400" />
|
||||
@@ -400,7 +404,7 @@
|
||||
<div class="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 mt-2 p-2 w-96 text-xs text-neutral-300 bg-neutral-700 border border-neutral-600 rounded-lg z-40">
|
||||
<h3 class="mb-2 font-semibold text-lg text-center">Choose a release asset</h3>
|
||||
<div class="select-wrapper">
|
||||
<select class="w-full bg-neutral-800!" bind:value={choice}>
|
||||
<select class="w-full bg-neutral-800!" bind:value={choice} aria-label="Release asset">
|
||||
{#each choices as choice, i}
|
||||
<option value={i}>{choice.name}</option>
|
||||
{/each}
|
||||
|
||||
@@ -1,9 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy, tick } from "svelte";
|
||||
|
||||
export let show = false;
|
||||
export let label = "";
|
||||
|
||||
let popupEl: HTMLDivElement;
|
||||
let previousFocus: HTMLElement | null = null;
|
||||
|
||||
$: if (show) {
|
||||
previousFocus = document.activeElement as HTMLElement | null;
|
||||
tick().then(() => popupEl?.focus());
|
||||
} else if (previousFocus) {
|
||||
previousFocus.focus();
|
||||
previousFocus = null;
|
||||
}
|
||||
|
||||
onDestroy(() => previousFocus?.focus());
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<div class="absolute top-0 left-0 m-2 p-4 w-[calc(100%-1rem)] h-[calc(100%-1rem)] bg-neutral-800 border border-neutral-700 rounded-lg overflow-auto z-30">
|
||||
<div
|
||||
bind:this={popupEl}
|
||||
class="absolute top-0 left-0 m-2 p-4 w-[calc(100%-1rem)] h-[calc(100%-1rem)] bg-neutral-800 border border-neutral-700 rounded-lg overflow-auto z-30"
|
||||
role="dialog"
|
||||
tabindex="-1"
|
||||
aria-label={label}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
@@ -200,7 +200,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<Popup show={showPopup}>
|
||||
<Popup show={showPopup} label="{device.name} profiles">
|
||||
<button class="mr-1 float-right text-xl text-neutral-300" on:click={() => showPopup = false} aria-label="Close">✕</button>
|
||||
<h2 class="text-xl font-semibold text-neutral-300">{device.name}</h2>
|
||||
|
||||
@@ -278,7 +278,7 @@
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
<Popup show={showApplicationManager}>
|
||||
<Popup show={showApplicationManager} label="Application profiles">
|
||||
<button class="mr-1 float-right text-xl text-neutral-300" on:click={() => showApplicationManager = false} aria-label="Close">✕</button>
|
||||
<h2 class="text-xl font-semibold text-neutral-300">{device.name}</h2>
|
||||
<span class="text-sm text-neutral-400">If your application isn't listed, try switching to it and back again.</span>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<Popup show={showPopup}>
|
||||
<Popup show={showPopup} label="Settings">
|
||||
<button class="mr-2 my-1 float-right text-xl text-neutral-300" on:click={() => showPopup = false} aria-label="Close">✕</button>
|
||||
<h2 class="m-2 font-semibold text-xl text-neutral-300">Settings</h2>
|
||||
{#if $settings}
|
||||
|
||||
Reference in new issue
Block a user