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:
Florian Beijersandnekename authored and nekename committed 2026-04-01 23:01:58 +01:00
1 parent 37648f8636
commit 758214d92e
7 files changed
+45 -16

No files matched your search

+1 -1
View File
@@ -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";
+4 -2
View File
@@ -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>
+3 -2
View File
@@ -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>
+11 -7
View File
@@ -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}
+23 -1
View File
@@ -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}
+2 -2
View File
@@ -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>
+1 -1
View File
@@ -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}