Просмотр исходного кода

Merge pull request #14959 from itk-dev/feature/accessibility-edit-connection-modal

Feature/accessibility edit connection modal
Tim Jaeryang Baek 8 месяцев назад
Родитель
Сommit
42b8463fcc

+ 67 - 18
src/lib/components/AddConnectionModal.svelte

@@ -3,7 +3,7 @@
 	import { getContext, onMount } from 'svelte';
 	const i18n = getContext('i18n');
 
-	import { models } from '$lib/stores';
+	import { settings } from '$lib/stores';
 	import { verifyOpenAIConnection } from '$lib/apis/openai';
 	import { verifyOllamaConnection } from '$lib/apis/ollama';
 
@@ -258,11 +258,17 @@
 
 						<div class="flex gap-2 mt-1.5">
 							<div class="flex flex-col w-full">
-								<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('URL')}</div>
+								<label
+									for="url-input"
+									class={`mb-0.5 text-xs text-gray-500
+								${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : ''}`}
+									>{$i18n.t('URL')}</label
+								>
 
 								<div class="flex-1">
 									<input
-										class="w-full text-sm bg-transparent placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden"
+										id="url-input"
+										class={`w-full text-sm bg-transparent ${($settings?.highContrastMode ?? false) ? 'placeholder:text-gray-700 dark:placeholder:text-gray-100' : 'outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
 										type="text"
 										bind:value={url}
 										placeholder={$i18n.t('API Base URL')}
@@ -279,11 +285,13 @@
 										verifyHandler();
 									}}
 									type="button"
+									aria-label={$i18n.t('Verify Connection')}
 								>
 									<svg
 										xmlns="http://www.w3.org/2000/svg"
 										viewBox="0 0 20 20"
 										fill="currentColor"
+										aria-hidden="true"
 										class="w-4 h-4"
 									>
 										<path
@@ -296,19 +304,27 @@
 							</Tooltip>
 
 							<div class="flex flex-col shrink-0 self-end">
+								<label class="sr-only" for="toggle-connection"
+									>{$i18n.t('Toggle whether current connection is active.')}</label
+								>
 								<Tooltip content={enable ? $i18n.t('Enabled') : $i18n.t('Disabled')}>
-									<Switch bind:state={enable} />
+									<Switch id="toggle-connection" bind:state={enable} />
 								</Tooltip>
 							</div>
 						</div>
 
 						<div class="flex gap-2 mt-2">
 							<div class="flex flex-col w-full">
-								<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('Key')}</div>
+								<div
+									class={`mb-0.5 text-xs text-gray-500
+								${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : ''}`}
+								>
+									{$i18n.t('Key')}
+								</div>
 
 								<div class="flex-1">
 									<SensitiveInput
-										className="w-full text-sm bg-transparent placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden"
+										inputClassName={`w-full text-sm bg-transparent ${($settings?.highContrastMode ?? false) ? 'placeholder:text-gray-700 dark:placeholder:text-gray-100' : 'outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
 										bind:value={key}
 										placeholder={$i18n.t('API Key')}
 										required={false}
@@ -317,7 +333,12 @@
 							</div>
 
 							<div class="flex flex-col w-full">
-								<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Prefix ID')}</div>
+								<label
+									for="prefix-id-input"
+									class={`mb-0.5 text-xs text-gray-500
+								${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : ''}`}
+									>{$i18n.t('Prefix ID')}</label
+								>
 
 								<div class="flex-1">
 									<Tooltip
@@ -326,8 +347,9 @@
 										)}
 									>
 										<input
-											class="w-full text-sm bg-transparent placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden"
+											class={`w-full text-sm bg-transparent ${($settings?.highContrastMode ?? false) ? 'placeholder:text-gray-700 dark:placeholder:text-gray-100' : 'outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
 											type="text"
+											id="prefix-id-input"
 											bind:value={prefixId}
 											placeholder={$i18n.t('Prefix ID')}
 											autocomplete="off"
@@ -340,11 +362,17 @@
 						{#if azure}
 							<div class="flex gap-2 mt-2">
 								<div class="flex flex-col w-full">
-									<div class=" mb-1 text-xs text-gray-500">{$i18n.t('API Version')}</div>
+									<label
+										for="api-version-input"
+										class={`mb-0.5 text-xs text-gray-500
+								${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : ''}`}
+										>{$i18n.t('API Version')}</label
+									>
 
 									<div class="flex-1">
 										<input
-											class="w-full text-sm bg-transparent placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden"
+											id="api-version-input"
+											class={`w-full text-sm bg-transparent placeholder:text-gray-300 dark:placeholder:text-gray-700 ${($settings?.highContrastMode ?? false) ? 'placeholder:text-gray-700 dark:placeholder:text-gray-100' : 'outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
 											type="text"
 											bind:value={apiVersion}
 											placeholder={$i18n.t('API Version')}
@@ -358,7 +386,12 @@
 
 						<div class="flex gap-2 mt-2">
 							<div class="flex flex-col w-full">
-								<div class=" mb-1.5 text-xs text-gray-500">{$i18n.t('Tags')}</div>
+								<div
+									class={`mb-0.5 text-xs text-gray-500
+								${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : ''}`}
+								>
+									{$i18n.t('Tags')}
+								</div>
 
 								<div class="flex-1">
 									<Tags
@@ -383,18 +416,26 @@
 
 						<div class="flex flex-col w-full">
 							<div class="mb-1 flex justify-between">
-								<div class="text-xs text-gray-500">{$i18n.t('Model IDs')}</div>
+								<div
+									class={`mb-0.5 text-xs text-gray-500
+								${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : ''}`}
+								>
+									{$i18n.t('Model IDs')}
+								</div>
 							</div>
 
 							{#if modelIds.length > 0}
-								<div class="flex flex-col">
+								<ul class="flex flex-col">
 									{#each modelIds as modelId, modelIdx}
-										<div class=" flex gap-2 w-full justify-between items-center">
+										<li class=" flex gap-2 w-full justify-between items-center">
 											<div class=" text-sm flex-1 py-1 rounded-lg">
 												{modelId}
 											</div>
 											<div class="shrink-0">
 												<button
+													aria-label={$i18n.t(`Remove {{MODELID}} from list.`, {
+														MODELID: modelId
+													})}
 													type="button"
 													on:click={() => {
 														modelIds = modelIds.filter((_, idx) => idx !== modelIdx);
@@ -403,11 +444,14 @@
 													<Minus strokeWidth="2" className="size-3.5" />
 												</button>
 											</div>
-										</div>
+										</li>
 									{/each}
-								</div>
+								</ul>
 							{:else}
-								<div class="text-gray-500 text-xs text-center py-2 px-10">
+								<div
+									class={`text-gray-500 text-xs text-center py-2 px-10
+								${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : ''}`}
+								>
 									{#if ollama}
 										{$i18n.t('Leave empty to include all models from "{{url}}/api/tags" endpoint', {
 											url: url
@@ -429,17 +473,22 @@
 						<hr class=" border-gray-100 dark:border-gray-700/10 my-1.5 w-full" />
 
 						<div class="flex items-center">
+							<label class="sr-only" for="add-model-id-input">{$i18n.t('Add a model ID')}</label>
 							<input
 								class="w-full py-1 text-sm rounded-lg bg-transparent {modelId
 									? ''
-									: 'text-gray-500'} placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden"
+									: 'text-gray-500'} {($settings?.highContrastMode ?? false)
+									? 'dark:placeholder:text-gray-100 placeholder:text-gray-700'
+									: 'placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden'}"
 								bind:value={modelId}
+								id="add-model-id-input"
 								placeholder={$i18n.t('Add a model ID')}
 							/>
 
 							<div>
 								<button
 									type="button"
+									aria-label={$i18n.t('Add')}
 									on:click={() => {
 										addModelHandler();
 									}}

+ 2 - 0
src/lib/components/common/Switch.svelte

@@ -2,6 +2,7 @@
 	import { createEventDispatcher, tick } from 'svelte';
 	import { Switch } from 'bits-ui';
 	export let state = true;
+	export let id = '';
 
 	const dispatch = createEventDispatcher();
 
@@ -10,6 +11,7 @@
 
 <Switch.Root
 	bind:checked={state}
+	{id}
 	class="flex h-5 min-h-5 w-9 shrink-0 cursor-pointer items-center rounded-full px-[3px] mx-[1px] transition  {state
 		? ' bg-emerald-600'
 		: 'bg-gray-200 dark:bg-transparent'} outline outline-1 outline-gray-100 dark:outline-gray-800"

+ 2 - 2
src/lib/components/common/Tags.svelte

@@ -9,7 +9,7 @@
 	export let tags = [];
 </script>
 
-<div class="flex flex-row flex-wrap gap-1 line-clamp-1">
+<ul class="flex flex-row flex-wrap gap-1 line-clamp-1">
 	<TagList
 		{tags}
 		on:delete={(e) => {
@@ -23,4 +23,4 @@
 			dispatch('add', e.detail);
 		}}
 	/>
-</div>
+</ul>

+ 3 - 0
src/lib/components/common/Tags/TagInput.svelte

@@ -29,6 +29,7 @@
 				bind:value={tagName}
 				class=" px-2 cursor-pointer self-center text-xs h-fit bg-transparent outline-hidden line-clamp-1 w-[6.5rem]"
 				placeholder={$i18n.t('Add a tag')}
+				aria-label={$i18n.t('Add a tag')}
 				list="tagOptions"
 				on:keydown={(event) => {
 					if (event.key === 'Enter') {
@@ -48,6 +49,7 @@
 					viewBox="0 0 16 16"
 					fill="currentColor"
 					stroke-width="2"
+					aria-hidden="true"
 					class="w-3 h-3"
 				>
 					<path
@@ -72,6 +74,7 @@
 			<svg
 				xmlns="http://www.w3.org/2000/svg"
 				viewBox="0 0 16 16"
+				aria-hidden="true"
 				fill="currentColor"
 				class="w-3 h-3 {showTagInput ? 'rotate-45' : ''} transition-all transform"
 			>

+ 5 - 2
src/lib/components/common/Tags/TagList.svelte

@@ -1,5 +1,7 @@
 <script lang="ts">
 	import { createEventDispatcher } from 'svelte';
+	import { getContext } from 'svelte';
+	const i18n = getContext('i18n');
 	import Tooltip from '../Tooltip.svelte';
 	import XMark from '$lib/components/icons/XMark.svelte';
 	import Badge from '../Badge.svelte';
@@ -10,7 +12,7 @@
 
 {#each tags as tag}
 	<Tooltip content={tag.name}>
-		<div
+		<li
 			class="relative group/tags px-1.5 py-[0.2px] gap-0.5 flex justify-between h-fit max-h-fit w-fit items-center rounded-full bg-gray-500/20 text-gray-700 dark:text-gray-200 transition cursor-pointer"
 		>
 			<div class=" text-[0.7rem] font-medium self-center line-clamp-1 w-fit">
@@ -23,10 +25,11 @@
 						dispatch('delete', tag.name);
 					}}
 					type="button"
+					aria-label={$i18n.t('Remove this tag from list')}
 				>
 					<XMark className="size-3" strokeWidth="2.5" />
 				</button>
 			</div>
-		</div>
+		</li>
 	</Tooltip>
 {/each}

+ 1 - 0
src/lib/components/icons/Minus.svelte

@@ -6,6 +6,7 @@
 <svg
 	xmlns="http://www.w3.org/2000/svg"
 	fill="none"
+	aria-hidden="true"
 	viewBox="0 0 24 24"
 	stroke-width={strokeWidth}
 	stroke="currentColor"

+ 1 - 0
src/lib/components/icons/Plus.svelte

@@ -10,6 +10,7 @@
 	stroke-width={strokeWidth}
 	stroke="currentColor"
 	class={className}
+	aria-hidden="true"
 >
 	<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
 </svg>