mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
🚹 feat: Miscellaneous Accessibility Improvements (#10913)
* 🔱 fix: Fork Menu Accessibility Improvements (#10910) * feat: more accessible aria-label for fork button * fix: alignment between text and checkbox * feat: add text change on focus for parity with on hover for keyboard accessibility * 🤔 fix: Programmatic Expansion State for Thinking Button (#10912) * 🙋♂️ feat: Accessible Default User Icon Colors (#10909) * fix: downshift values for all non-compliant default bg-colors for user icons to achieve 4.5:1 contrast threshold minimums with text * 🚪 feat: Open Sidebar Label Accessibility (#10893) * feat: more accessible labelling on open / close sidebar
This commit is contained in:
parent
c9005c41a8
commit
7ea9cc06f2
5 changed files with 88 additions and 34 deletions
|
|
@ -65,6 +65,7 @@ export const ThinkingButton = memo(
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
aria-expanded={isExpanded}
|
||||||
className={cn(
|
className={cn(
|
||||||
'group/button flex flex-1 items-center justify-start rounded-lg leading-[18px]',
|
'group/button flex flex-1 items-center justify-start rounded-lg leading-[18px]',
|
||||||
fontSize,
|
fontSize,
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,21 @@ const PopoverButton: React.FC<PopoverButtonProps> = ({
|
||||||
setActiveSetting(optionLabels[ForkOptions.DEFAULT]);
|
setActiveSetting(optionLabels[ForkOptions.DEFAULT]);
|
||||||
}, 175);
|
}, 175);
|
||||||
}}
|
}}
|
||||||
|
onFocus={() => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
timeoutRef.current = null;
|
||||||
|
}
|
||||||
|
setActiveSetting(optionLabels[setting]);
|
||||||
|
}}
|
||||||
|
onBlur={() => {
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
setActiveSetting(optionLabels[ForkOptions.DEFAULT]);
|
||||||
|
}, 175);
|
||||||
|
}}
|
||||||
className="mx-0.5 w-14 flex-1 rounded-xl border-2 border-border-medium bg-surface-secondary text-text-secondary transition duration-200 ease-in-out hover:bg-surface-hover hover:text-text-primary"
|
className="mx-0.5 w-14 flex-1 rounded-xl border-2 border-border-medium bg-surface-secondary text-text-secondary transition duration-200 ease-in-out hover:bg-surface-hover hover:text-text-primary"
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
>
|
>
|
||||||
|
|
@ -134,35 +149,36 @@ const CheckboxOption: React.FC<CheckboxOptionProps> = ({
|
||||||
const { showToast } = useToastContext();
|
const { showToast } = useToastContext();
|
||||||
return (
|
return (
|
||||||
<Ariakit.HovercardProvider placement="right-start">
|
<Ariakit.HovercardProvider placement="right-start">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex h-6 w-full select-none items-center justify-start rounded-md text-sm text-text-secondary hover:text-text-primary">
|
<Ariakit.HovercardAnchor
|
||||||
<Ariakit.HovercardAnchor
|
render={
|
||||||
render={
|
<div className="flex items-center">
|
||||||
<div>
|
<Ariakit.Checkbox
|
||||||
<Ariakit.Checkbox
|
id={id}
|
||||||
id={id}
|
checked={checked}
|
||||||
checked={checked}
|
onChange={(e) => {
|
||||||
onChange={(e) => {
|
const value = e.target.checked;
|
||||||
const value = e.target.checked;
|
if (value && showToastOnCheck) {
|
||||||
if (value && showToastOnCheck) {
|
showToast({
|
||||||
showToast({
|
message: localize('com_ui_fork_remember_checked'),
|
||||||
message: localize('com_ui_fork_remember_checked'),
|
status: 'info',
|
||||||
status: 'info',
|
});
|
||||||
});
|
}
|
||||||
}
|
onToggle(value);
|
||||||
onToggle(value);
|
}}
|
||||||
}}
|
className="h-4 w-4 rounded-sm border border-primary ring-offset-background transition duration-300 ease-in-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground"
|
||||||
className="h-4 w-4 rounded-sm border border-primary ring-offset-background transition duration-300 ease-in-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground"
|
aria-label={localize(labelKey)}
|
||||||
aria-label={localize(labelKey)}
|
/>
|
||||||
/>
|
<label
|
||||||
<label htmlFor={id} className="ml-2 cursor-pointer">
|
htmlFor={id}
|
||||||
{localize(labelKey)}
|
className="ml-2 cursor-pointer select-none text-sm text-text-secondary hover:text-text-primary"
|
||||||
</label>
|
>
|
||||||
</div>
|
{localize(labelKey)}
|
||||||
}
|
</label>
|
||||||
/>
|
</div>
|
||||||
</div>
|
}
|
||||||
<Ariakit.HovercardDisclosure className="rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-ring">
|
/>
|
||||||
|
<Ariakit.HovercardDisclosure className="ml-1 rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-ring">
|
||||||
<VisuallyHidden>{localize(infoKey)}</VisuallyHidden>
|
<VisuallyHidden>{localize(infoKey)}</VisuallyHidden>
|
||||||
{chevronDown}
|
{chevronDown}
|
||||||
</Ariakit.HovercardDisclosure>
|
</Ariakit.HovercardDisclosure>
|
||||||
|
|
@ -331,7 +347,7 @@ export default function Fork({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={localize('com_ui_fork')}
|
aria-label={localize('com_ui_fork_open_menu')}
|
||||||
>
|
>
|
||||||
<GitFork size="19" />
|
<GitFork size="19" />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,23 @@ export default function NavToggle({
|
||||||
const topBarRotation = side === 'right' ? `-${rotation}` : rotation;
|
const topBarRotation = side === 'right' ? `-${rotation}` : rotation;
|
||||||
const bottomBarRotation = side === 'right' ? rotation : `-${rotation}`;
|
const bottomBarRotation = side === 'right' ? rotation : `-${rotation}`;
|
||||||
|
|
||||||
|
let sidebarLabel;
|
||||||
|
let actionKey;
|
||||||
|
|
||||||
|
if (side === 'left') {
|
||||||
|
sidebarLabel = localize('com_ui_chat_history');
|
||||||
|
} else {
|
||||||
|
sidebarLabel = localize('com_nav_control_panel');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (navVisible) {
|
||||||
|
actionKey = 'com_ui_close_var';
|
||||||
|
} else {
|
||||||
|
actionKey = 'com_ui_open_var';
|
||||||
|
}
|
||||||
|
|
||||||
|
const ariaDescription = localize(actionKey, { 0: sidebarLabel });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -42,15 +59,13 @@ export default function NavToggle({
|
||||||
>
|
>
|
||||||
<TooltipAnchor
|
<TooltipAnchor
|
||||||
side={side === 'right' ? 'left' : 'right'}
|
side={side === 'right' ? 'left' : 'right'}
|
||||||
aria-label={side === 'left' ? localize('com_ui_chat_history') : localize('com_ui_controls')}
|
aria-label={ariaDescription}
|
||||||
aria-expanded={navVisible}
|
aria-expanded={navVisible}
|
||||||
aria-controls={side === 'left' ? 'chat-history-nav' : 'controls-nav'}
|
aria-controls={side === 'left' ? 'chat-history-nav' : 'controls-nav'}
|
||||||
id={`toggle-${side}-nav`}
|
id={`toggle-${side}-nav`}
|
||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
role="button"
|
role="button"
|
||||||
description={
|
description={ariaDescription}
|
||||||
navVisible ? localize('com_nav_close_sidebar') : localize('com_nav_open_sidebar')
|
|
||||||
}
|
|
||||||
className="flex items-center justify-center"
|
className="flex items-center justify-center"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -440,6 +440,7 @@
|
||||||
"com_nav_clear_conversation_confirm_message": "Are you sure you want to clear all conversations? This is irreversible.",
|
"com_nav_clear_conversation_confirm_message": "Are you sure you want to clear all conversations? This is irreversible.",
|
||||||
"com_nav_close_sidebar": "Close sidebar",
|
"com_nav_close_sidebar": "Close sidebar",
|
||||||
"com_nav_commands": "Commands",
|
"com_nav_commands": "Commands",
|
||||||
|
"com_nav_control_panel": "Control Panel",
|
||||||
"com_nav_confirm_clear": "Confirm Clear",
|
"com_nav_confirm_clear": "Confirm Clear",
|
||||||
"com_nav_conversation_mode": "Conversation Mode",
|
"com_nav_conversation_mode": "Conversation Mode",
|
||||||
"com_nav_convo_menu_options": "Conversation Menu Options",
|
"com_nav_convo_menu_options": "Conversation Menu Options",
|
||||||
|
|
@ -788,6 +789,7 @@
|
||||||
"com_ui_client_secret": "Client Secret",
|
"com_ui_client_secret": "Client Secret",
|
||||||
"com_ui_close": "Close",
|
"com_ui_close": "Close",
|
||||||
"com_ui_close_menu": "Close Menu",
|
"com_ui_close_menu": "Close Menu",
|
||||||
|
"com_ui_close_var": "Close {{0}}",
|
||||||
"com_ui_close_settings": "Close Settings",
|
"com_ui_close_settings": "Close Settings",
|
||||||
"com_ui_close_window": "Close Window",
|
"com_ui_close_window": "Close Window",
|
||||||
"com_ui_code": "Code",
|
"com_ui_code": "Code",
|
||||||
|
|
@ -979,6 +981,7 @@
|
||||||
"com_ui_fork_info_visible": "This option forks only the visible messages; in other words, the direct path to the target message, without any branches.",
|
"com_ui_fork_info_visible": "This option forks only the visible messages; in other words, the direct path to the target message, without any branches.",
|
||||||
"com_ui_fork_more_details_about": "View additional information and details about the \"{{0}}\" fork option",
|
"com_ui_fork_more_details_about": "View additional information and details about the \"{{0}}\" fork option",
|
||||||
"com_ui_fork_more_info_options": "View detailed explanation of all fork options and their behaviors",
|
"com_ui_fork_more_info_options": "View detailed explanation of all fork options and their behaviors",
|
||||||
|
"com_ui_fork_open_menu": "Open Fork Menu",
|
||||||
"com_ui_fork_processing": "Forking conversation...",
|
"com_ui_fork_processing": "Forking conversation...",
|
||||||
"com_ui_fork_remember": "Remember",
|
"com_ui_fork_remember": "Remember",
|
||||||
"com_ui_fork_remember_checked": "Your selection will be remembered after usage. Change this at any time in the settings.",
|
"com_ui_fork_remember_checked": "Your selection will be remembered after usage. Change this at any time in the settings.",
|
||||||
|
|
@ -1268,6 +1271,7 @@
|
||||||
"com_ui_share_var": "Share {{0}}",
|
"com_ui_share_var": "Share {{0}}",
|
||||||
"com_ui_shared_link_delete_success": "Successfully deleted shared link",
|
"com_ui_shared_link_delete_success": "Successfully deleted shared link",
|
||||||
"com_ui_shared_link_not_found": "Shared link not found",
|
"com_ui_shared_link_not_found": "Shared link not found",
|
||||||
|
"com_ui_open_var": "Open {{0}}",
|
||||||
"com_ui_shared_prompts": "Shared Prompts",
|
"com_ui_shared_prompts": "Shared Prompts",
|
||||||
"com_ui_shop": "Shopping",
|
"com_ui_shop": "Shopping",
|
||||||
"com_ui_show_all": "Show All",
|
"com_ui_show_all": "Show All",
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,24 @@ const useAvatar = (user: TUser | undefined) => {
|
||||||
seed,
|
seed,
|
||||||
fontFamily: ['Verdana'],
|
fontFamily: ['Verdana'],
|
||||||
fontSize: 36,
|
fontSize: 36,
|
||||||
|
backgroundType: ['solid'],
|
||||||
|
backgroundColor: [
|
||||||
|
'd81b60',
|
||||||
|
'8e24aa',
|
||||||
|
'5e35b1',
|
||||||
|
'3949ab',
|
||||||
|
'DB3733',
|
||||||
|
'1B79CC',
|
||||||
|
'027CB8',
|
||||||
|
'008291',
|
||||||
|
'008577',
|
||||||
|
'58802F',
|
||||||
|
'8A761D',
|
||||||
|
'9C6D00',
|
||||||
|
'B06200',
|
||||||
|
'D1451A',
|
||||||
|
],
|
||||||
|
textColor: ['ffffff'],
|
||||||
});
|
});
|
||||||
|
|
||||||
let avatarDataUri = '';
|
let avatarDataUri = '';
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue