️ fix: Accessibility, UI consistency, dialog & avatar refactors (#9975)

* 🔧 refactor: Improve accessibility and styling in ChatGroupItem and FilterPrompts components

* 🔧 fix: Add button type and keyboard accessibility to dropdown menu trigger in ChatGroupItem

* 🔧 fix(757): Enhance accessibility by updating aria-labels and adding localization for prompt groups

* 🔧 fix(618): Update version to 0.3.1 and enhance accessibility in InfoHoverCard component

* 🔧 fix(618): Update aria-label in InfoHoverCard to use dynamic text prop for improved accessibility

* 🔧 fix: Enhance accessibility by updating aria-labels and roles in Conversations components

* 🔧 fix(620): Enhance accessibility by adding tabIndex to Tabs.Content components in ArtifactTabs, Settings, and Speech components

* refactor: remove RevokeKeysButton component and update related components for accessibility

- Deleted RevokeKeysButton component.
- Updated SharedLinks and General components to use Label for accessibility.
- Enhanced Personalization component with aria-labelledby and aria-describedby attributes.
- Refactored ConversationModeSwitch to use ToggleSwitch for better state management.
- Improved AutoSendTextSelector with local state management and accessibility attributes.
- Replaced Switch components with ToggleSwitch in various Speech and TTS components for consistency.
- Added aria-labelledby attributes to Dropdown components for better accessibility.
- Updated translation.json to include new localization keys and improved existing ones.
- Enhanced Slider component to support aria attributes for better accessibility.

* 🔧 fix: Enhance user feedback for API key operations with success and error messages

* 🔧 fix: Update aria-labels in Avatar component for improved localization and accessibility

* 🔧 fix: Refactor handleFile and handleDrop functions for improved readability and maintainability
This commit is contained in:
Marco Beretta 2025-10-07 20:12:49 +02:00 committed by GitHub
parent bcd97aad2f
commit a5189052ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 1158 additions and 857 deletions

View file

@ -1,6 +1,4 @@
import { useRecoilState } from 'recoil';
import { Switch } from '@librechat/client';
import { useLocalize } from '~/hooks';
import ToggleSwitch from '../../ToggleSwitch';
import store from '~/store';
export default function AutomaticPlaybackSwitch({
@ -8,26 +6,12 @@ export default function AutomaticPlaybackSwitch({
}: {
onCheckedChange?: (value: boolean) => void;
}) {
const localize = useLocalize();
const [automaticPlayback, setAutomaticPlayback] = useRecoilState(store.automaticPlayback);
const handleCheckedChange = (value: boolean) => {
setAutomaticPlayback(value);
if (onCheckedChange) {
onCheckedChange(value);
}
};
return (
<div className="flex items-center justify-between">
<div>{localize('com_nav_automatic_playback')}</div>
<Switch
id="AutomaticPlayback"
checked={automaticPlayback}
onCheckedChange={handleCheckedChange}
className="ml-4"
data-testid="AutomaticPlayback"
/>
</div>
<ToggleSwitch
stateAtom={store.automaticPlayback}
localizationKey={'com_nav_automatic_playback' as const}
switchId="AutomaticPlayback"
onCheckedChange={onCheckedChange}
/>
);
}

View file

@ -1,6 +1,5 @@
import { useRecoilState } from 'recoil';
import { Switch } from '@librechat/client';
import { useLocalize } from '~/hooks';
import { useRecoilValue } from 'recoil';
import ToggleSwitch from '../../ToggleSwitch';
import store from '~/store';
export default function CacheTTSSwitch({
@ -8,28 +7,15 @@ export default function CacheTTSSwitch({
}: {
onCheckedChange?: (value: boolean) => void;
}) {
const localize = useLocalize();
const [cacheTTS, setCacheTTS] = useRecoilState<boolean>(store.cacheTTS);
const [textToSpeech] = useRecoilState<boolean>(store.textToSpeech);
const handleCheckedChange = (value: boolean) => {
setCacheTTS(value);
if (onCheckedChange) {
onCheckedChange(value);
}
};
const textToSpeech = useRecoilValue(store.textToSpeech);
return (
<div className="flex items-center justify-between">
<div>{localize('com_nav_enable_cache_tts')}</div>
<Switch
id="CacheTTS"
checked={cacheTTS}
onCheckedChange={handleCheckedChange}
className="ml-4"
data-testid="CacheTTS"
disabled={!textToSpeech}
/>
</div>
<ToggleSwitch
stateAtom={store.cacheTTS}
localizationKey={'com_nav_enable_cache_tts' as const}
switchId="CacheTTS"
onCheckedChange={onCheckedChange}
disabled={!textToSpeech}
/>
);
}

View file

@ -1,6 +1,5 @@
import { useRecoilState } from 'recoil';
import { Switch } from '@librechat/client';
import { useLocalize } from '~/hooks';
import { useRecoilValue } from 'recoil';
import ToggleSwitch from '../../ToggleSwitch';
import store from '~/store';
export default function CloudBrowserVoicesSwitch({
@ -8,30 +7,15 @@ export default function CloudBrowserVoicesSwitch({
}: {
onCheckedChange?: (value: boolean) => void;
}) {
const localize = useLocalize();
const [cloudBrowserVoices, setCloudBrowserVoices] = useRecoilState<boolean>(
store.cloudBrowserVoices,
);
const [textToSpeech] = useRecoilState<boolean>(store.textToSpeech);
const handleCheckedChange = (value: boolean) => {
setCloudBrowserVoices(value);
if (onCheckedChange) {
onCheckedChange(value);
}
};
const textToSpeech = useRecoilValue(store.textToSpeech);
return (
<div className="flex items-center justify-between">
<div>{localize('com_nav_enable_cloud_browser_voice')}</div>
<Switch
id="CloudBrowserVoices"
checked={cloudBrowserVoices}
onCheckedChange={handleCheckedChange}
className="ml-4"
data-testid="CloudBrowserVoices"
disabled={!textToSpeech}
/>
</div>
<ToggleSwitch
stateAtom={store.cloudBrowserVoices}
localizationKey={'com_nav_enable_cloud_browser_voice' as const}
switchId="CloudBrowserVoices"
onCheckedChange={onCheckedChange}
disabled={!textToSpeech}
/>
);
}

View file

@ -23,9 +23,11 @@ const EngineTTSDropdown: React.FC<EngineTTSDropdownProps> = ({ external }) => {
setEngineTTS(value);
};
const labelId = 'engine-tts-dropdown-label';
return (
<div className="flex items-center justify-between">
<div>{localize('com_nav_engine')}</div>
<div id={labelId}>{localize('com_nav_engine')}</div>
<Dropdown
value={engineTTS}
onChange={handleSelect}
@ -33,6 +35,7 @@ const EngineTTSDropdown: React.FC<EngineTTSDropdownProps> = ({ external }) => {
sizeClasses="w-[180px]"
testId="EngineTTSDropdown"
className="z-50"
aria-labelledby={labelId}
/>
</div>
);

View file

@ -13,7 +13,7 @@ export default function DecibelSelector() {
return (
<div className="flex items-center justify-between">
<div className="flex items-center justify-between">
<div>{localize('com_nav_playback_rate')}</div>
<div id="playback-rate-label">{localize('com_nav_playback_rate')}</div>
<div className="w-2" />
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: '1' })})
@ -29,6 +29,7 @@ export default function DecibelSelector() {
step={0.1}
className="ml-4 flex h-4 w-24"
disabled={!textToSpeech}
aria-labelledby="playback-rate-label"
/>
<div className="w-2" />
<InputNumber
@ -37,6 +38,7 @@ export default function DecibelSelector() {
onChange={(value) => setPlaybackRate(value ? value[0] : 0)}
min={0.1}
max={2}
aria-labelledby="playback-rate-label"
className={cn(
defaultTextProps,
cn(

View file

@ -1,6 +1,4 @@
import { useRecoilState } from 'recoil';
import { Switch } from '@librechat/client';
import { useLocalize } from '~/hooks';
import ToggleSwitch from '../../ToggleSwitch';
import store from '~/store';
export default function TextToSpeechSwitch({
@ -8,28 +6,13 @@ export default function TextToSpeechSwitch({
}: {
onCheckedChange?: (value: boolean) => void;
}) {
const localize = useLocalize();
const [TextToSpeech, setTextToSpeech] = useRecoilState<boolean>(store.textToSpeech);
const handleCheckedChange = (value: boolean) => {
setTextToSpeech(value);
if (onCheckedChange) {
onCheckedChange(value);
}
};
return (
<div className="flex items-center justify-between">
<div>
<strong>{localize('com_nav_text_to_speech')}</strong>
</div>
<Switch
id="TextToSpeech"
checked={TextToSpeech}
onCheckedChange={handleCheckedChange}
className="ml-4"
data-testid="TextToSpeech"
/>
</div>
<ToggleSwitch
stateAtom={store.textToSpeech}
localizationKey={'com_nav_text_to_speech' as const}
switchId="TextToSpeech"
onCheckedChange={onCheckedChange}
strongLabel={true}
/>
);
}