mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
☰ fix: Side Panel Accessibility Improvements (#10830)
* fix: pad cards so focus outline doesn't clip in prompts list * feat: pad snippet top for space between text and button * fix: prompt menu focus outline clipping with overflow-visible * fix: clipping in AgentBuilder for advanced and admin buttons * fix: clipping in memory panel for admin settings * fix: better contrast thresholds on focus outlines for admin settings and advanced buttons in agent builder * fix: better contrast thresholds on focus outlines for admin settings button in memory panel * fix: clipping on focus outline for manage files button in files panel * fix: focus outline clipping table cells for files panel table * fix: clipping on new bookmark button in bookmarks panel * fix: clipping on Admin Settings button in MCP Settings panel * fix: better contrast threshold outline and aria-label for Admin Settings button in MCP Settings panel * fix: misaligned globe because of new unnested menu button positioning * fix: localize global group aria-label * fix: screen reader not reading out proper prompt name for dropdown menu button
This commit is contained in:
parent
9e67eee294
commit
6fc6471010
15 changed files with 32 additions and 23 deletions
|
|
@ -55,7 +55,7 @@ function ChatGroupItem({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="relative my-2 items-stretch justify-between rounded-xl border border-border-light shadow-sm transition-all duration-300 ease-in-out hover:bg-surface-tertiary hover:shadow-lg">
|
||||
<div className="relative my-2 items-stretch justify-between rounded-xl border border-border-light px-1 shadow-sm transition-all duration-300 ease-in-out hover:bg-surface-tertiary hover:shadow-lg">
|
||||
<ListCard
|
||||
name={group.name}
|
||||
category={group.category ?? ''}
|
||||
|
|
@ -65,13 +65,15 @@ function ChatGroupItem({
|
|||
? group.oneliner
|
||||
: (group.productionPrompt?.prompt ?? '')
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
{groupIsGlobal === true && (
|
||||
<EarthIcon className="icon-md text-green-400" aria-label="Global prompt group" />
|
||||
)}
|
||||
></ListCard>
|
||||
{groupIsGlobal === true && (
|
||||
<div className="absolute right-14 top-[16px]">
|
||||
<EarthIcon
|
||||
className="icon-md text-green-400"
|
||||
aria-label={localize('com_ui_sr_global_prompt')}
|
||||
/>
|
||||
</div>
|
||||
</ListCard>
|
||||
)}
|
||||
<div className="absolute right-0 top-0 mr-1 mt-2.5 items-start pl-2">
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
|
@ -79,7 +81,7 @@ function ChatGroupItem({
|
|||
ref={triggerButtonRef}
|
||||
id={`prompt-actions-${group._id}`}
|
||||
type="button"
|
||||
aria-label={localize('com_ui_sr_actions_menu', { name: group.name })}
|
||||
aria-label={localize('com_ui_sr_actions_menu', { 0: group.name })}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export default function GroupSidePanel({
|
|||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-1 flex-col gap-2 overflow-y-auto">
|
||||
<div className="flex flex-1 flex-col gap-2 overflow-visible">
|
||||
{children}
|
||||
<div className={cn('relative flex h-full flex-col', isChatRoute ? '' : 'px-2 md:px-0')}>
|
||||
<List
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export default function ListCard({
|
|||
</div>
|
||||
<div
|
||||
id={`card-snippet-${name}`}
|
||||
className="ellipsis max-w-full select-none text-balance text-sm text-text-secondary"
|
||||
className="ellipsis max-w-full select-none text-balance pt-1 text-sm text-text-secondary"
|
||||
>
|
||||
{snippet}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ const AdminSettings = () => {
|
|||
<Button
|
||||
size={'sm'}
|
||||
variant={'outline'}
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium"
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary"
|
||||
aria-label={localize('com_ui_admin_settings')}
|
||||
>
|
||||
<ShieldEllipsis className="cursor-pointer" aria-hidden="true" />
|
||||
|
|
@ -218,7 +218,7 @@ const AdminSettings = () => {
|
|||
type="button"
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
disabled={isSubmitting || isLoading}
|
||||
className="btn rounded bg-green-500 font-bold text-white transition-all hover:bg-green-600"
|
||||
className="btn rounded bg-green-500 font-bold text-white transition-all hover:bg-green-600 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring-primary"
|
||||
>
|
||||
{localize('com_ui_save')}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const AdvancedButton: React.FC<AdvancedButtonProps> = ({ setActivePanel }) => {
|
|||
<Button
|
||||
size={'sm'}
|
||||
variant={'outline'}
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium"
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary"
|
||||
onClick={() => setActivePanel(Panel.advanced)}
|
||||
aria-label={localize('com_ui_advanced')}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ export default function AgentPanel() {
|
|||
<FormProvider {...methods}>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="scrollbar-gutter-stable h-auto w-full flex-shrink-0 overflow-x-hidden"
|
||||
className="scrollbar-gutter-stable h-auto w-full flex-shrink-0 overflow-x-visible"
|
||||
aria-label="Agent configuration form"
|
||||
>
|
||||
<div className="mx-1 mt-2 flex w-full flex-wrap gap-2">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const BookmarkPanel = () => {
|
|||
const { data } = useConversationTagsQuery();
|
||||
|
||||
return (
|
||||
<div className="h-auto max-w-full overflow-x-hidden">
|
||||
<div className="h-auto max-w-full overflow-x-visible">
|
||||
<BookmarkContext.Provider value={{ bookmarks: data || [] }}>
|
||||
<BookmarkTable />
|
||||
</BookmarkContext.Provider>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export default function FilesPanel() {
|
|||
const { data: files = [] } = useGetFiles<TFile[]>();
|
||||
|
||||
return (
|
||||
<div className="h-auto max-w-full overflow-x-hidden">
|
||||
<div className="h-auto max-w-full overflow-x-visible">
|
||||
<DataTable columns={columns} data={files} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -241,6 +241,11 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
|
|||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
className={
|
||||
isFilenameCell
|
||||
? 'focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-text-primary'
|
||||
: ''
|
||||
}
|
||||
data-skip-refocus="true"
|
||||
key={cell.id}
|
||||
role={isFilenameCell ? 'button' : undefined}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,8 @@ const MCPAdminSettings = () => {
|
|||
<Button
|
||||
size={'sm'}
|
||||
variant={'outline'}
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium"
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary"
|
||||
aria-label={localize('com_ui_admin_settings')}
|
||||
>
|
||||
<ShieldEllipsis className="cursor-pointer" aria-hidden="true" />
|
||||
{localize('com_ui_admin_settings')}
|
||||
|
|
@ -216,7 +217,7 @@ const MCPAdminSettings = () => {
|
|||
type="button"
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
disabled={isSubmitting || isLoading}
|
||||
className="btn rounded bg-green-500 font-bold text-white transition-all hover:bg-green-600"
|
||||
className="btn rounded bg-green-500 font-bold text-white transition-all hover:bg-green-600 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary"
|
||||
>
|
||||
{localize('com_ui_save')}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default function MCPBuilderPanel() {
|
|||
const configDialogProps = getConfigDialogProps();
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col overflow-hidden">
|
||||
<div className="flex h-full w-full flex-col overflow-visible">
|
||||
<div role="region" aria-label="MCP Builder" className="mt-2 space-y-2">
|
||||
{/* Admin Settings Button */}
|
||||
<MCPAdminSettings />
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ const AdminSettings = () => {
|
|||
<Button
|
||||
size={'sm'}
|
||||
variant={'outline'}
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium"
|
||||
className="btn btn-neutral border-token-border-light relative h-9 w-full gap-1 rounded-lg font-medium focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary"
|
||||
aria-label={localize('com_ui_admin_settings')}
|
||||
>
|
||||
<ShieldEllipsis className="cursor-pointer" aria-hidden="true" />
|
||||
|
|
@ -206,7 +206,7 @@ const AdminSettings = () => {
|
|||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting || isLoading}
|
||||
className="btn rounded bg-green-500 font-bold text-white transition-all hover:bg-green-600"
|
||||
className="btn rounded bg-green-500 font-bold text-white transition-all hover:bg-green-600 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary"
|
||||
>
|
||||
{localize('com_ui_save')}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ export default function MemoryViewer() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col overflow-hidden">
|
||||
<div className="flex h-full w-full flex-col">
|
||||
<div role="region" aria-label={localize('com_ui_memories')} className="mt-2 space-y-2">
|
||||
<div className="relative">
|
||||
<Input
|
||||
|
|
|
|||
|
|
@ -1285,6 +1285,7 @@
|
|||
"com_ui_special_variables_more_info": "You can select special variables from the dropdown: `{{current_date}}` (today's date and day of week), `{{current_datetime}}` (local date and time), `{{utc_iso_datetime}}` (UTC ISO datetime), and `{{current_user}}` (your account name).",
|
||||
"com_ui_speech_while_submitting": "Can't submit speech while a response is being generated",
|
||||
"com_ui_sr_actions_menu": "Open actions menu for \"{{0}}\" prompt",
|
||||
"com_ui_sr_global_prompt": "Global prompt group",
|
||||
"com_ui_stack_trace": "Stack Trace",
|
||||
"com_ui_status_prefix": "Status:",
|
||||
"com_ui_stop": "Stop",
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ const AccordionContent = React.forwardRef<
|
|||
>(({ className = '', children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Content
|
||||
ref={ref}
|
||||
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||
className="overflow-x-visible text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||
{...props}
|
||||
>
|
||||
<div className={cn('pb-4 pt-0', className)}>{children}</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue