mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-20 18:30:15 +01:00
🤲 a11y: Sidebar Text Contrast (#3665)
* fix: use theme class for valid contrast for light/dark, conversation group names, fix type issues * fix: searchbar text contrast styling, closes #3469 * style: add theming for prompt cards, fix a11y contrast issues * a11y: address placeholder text contrast issues in LLM controls section * chore: Add conditional check for pull request repository in a11y workflow * style: Update text color contrast to WCAG standard for placeholder and focus states in AssistantPanel components
This commit is contained in:
parent
f8a5dad265
commit
91fc89076f
16 changed files with 62 additions and 51 deletions
|
|
@ -2,7 +2,6 @@ import { useState, useMemo } from 'react';
|
|||
import { Menu as MenuIcon, Edit as EditIcon, EarthIcon, TextSearch } from 'lucide-react';
|
||||
import type { TPromptGroup } from 'librechat-data-provider';
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuGroup,
|
||||
|
|
@ -29,12 +28,12 @@ export default function ChatGroupItem({
|
|||
const [isVariableDialogOpen, setVariableDialogOpen] = useState(false);
|
||||
const onEditClick = useCustomLink<HTMLDivElement>(`/d/prompts/${group._id}`);
|
||||
const groupIsGlobal = useMemo(
|
||||
() => instanceProjectId && group.projectIds?.includes(instanceProjectId),
|
||||
() => instanceProjectId != null && group.projectIds?.includes(instanceProjectId),
|
||||
[group, instanceProjectId],
|
||||
);
|
||||
const isOwner = useMemo(() => user?.id === group.author, [user, group]);
|
||||
|
||||
const onCardClick = () => {
|
||||
const onCardClick: React.MouseEventHandler<HTMLButtonElement> = () => {
|
||||
const text = group.productionPrompt?.prompt ?? '';
|
||||
if (!text) {
|
||||
return;
|
||||
|
|
@ -53,23 +52,26 @@ export default function ChatGroupItem({
|
|||
name={group.name}
|
||||
category={group.category ?? ''}
|
||||
onClick={onCardClick}
|
||||
snippet={group.oneliner ? group.oneliner : group.productionPrompt?.prompt ?? ''}
|
||||
snippet={
|
||||
typeof group.oneliner === 'string' && group.oneliner.length > 0
|
||||
? group.oneliner
|
||||
: group.productionPrompt?.prompt ?? ''
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
{groupIsGlobal && <EarthIcon className="icon-md text-green-400" />}
|
||||
{groupIsGlobal === true && <EarthIcon className="icon-md text-green-400" />}
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
id="promtps-menu-trigger"
|
||||
aria-label="promtps-menu-trigger"
|
||||
variant="outline"
|
||||
<button
|
||||
id="prompts-menu-trigger"
|
||||
aria-label="prompts-menu-trigger"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
className="z-50 h-7 w-7 p-0 transition-all duration-300 ease-in-out hover:border-white dark:bg-gray-800 dark:hover:border-gray-400 dark:focus:border-gray-500"
|
||||
className="z-50 inline-flex h-7 w-7 items-center justify-center rounded-md border border-border-medium bg-transparent p-0 text-sm font-medium transition-all duration-300 ease-in-out hover:border-border-heavy hover:bg-surface-secondary focus:border-border-heavy focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
<MenuIcon className="icon-md dark:text-gray-300" />
|
||||
</Button>
|
||||
<MenuIcon className="icon-md text-text-secondary" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
className="z-50 mt-2 w-36 rounded-lg"
|
||||
|
|
@ -81,7 +83,7 @@ export default function ChatGroupItem({
|
|||
e.stopPropagation();
|
||||
setPreviewDialogOpen(true);
|
||||
}}
|
||||
className="w-full cursor-pointer rounded-lg disabled:cursor-not-allowed dark:text-gray-300 dark:hover:bg-gray-700 dark:focus:bg-gray-700"
|
||||
className="w-full cursor-pointer rounded-lg text-text-secondary hover:bg-surface-hover focus:bg-surface-hover disabled:cursor-not-allowed"
|
||||
>
|
||||
<TextSearch className="mr-2 h-4 w-4" />
|
||||
<span>{localize('com_ui_preview')}</span>
|
||||
|
|
@ -90,7 +92,7 @@ export default function ChatGroupItem({
|
|||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
disabled={!isOwner}
|
||||
className="cursor-pointer rounded-lg disabled:cursor-not-allowed dark:text-gray-300 dark:hover:bg-gray-700 dark:focus:bg-gray-700"
|
||||
className="cursor-pointer rounded-lg text-text-secondary hover:bg-surface-hover focus:bg-surface-hover disabled:cursor-not-allowed"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onEditClick(e);
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ export default function FilterPrompts({
|
|||
setDisplayName(e.target.value);
|
||||
setName(e.target.value);
|
||||
}}
|
||||
className="w-full border-border-light"
|
||||
className="w-full border-border-light placeholder:text-text-secondary"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,27 +10,25 @@ export default function ListCard({
|
|||
category: string;
|
||||
name: string;
|
||||
snippet: string;
|
||||
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
||||
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
<button
|
||||
onClick={onClick}
|
||||
className="relative my-2 flex w-full cursor-pointer flex-col gap-2 rounded-2xl border px-3 pb-4 pt-3 text-start align-top
|
||||
text-[15px] shadow-[0_0_2px_0_rgba(0,0,0,0.05),0_4px_6px_0_rgba(0,0,0,0.02)] transition-all duration-300 ease-in-out hover:bg-gray-100 dark:border-gray-700 dark:hover:bg-gray-700"
|
||||
className="relative my-2 flex w-full cursor-pointer flex-col gap-2 rounded-2xl border border-border-light px-3 pb-4 pt-3 text-start
|
||||
align-top text-[15px] shadow-[0_0_2px_0_rgba(0,0,0,0.05),0_4px_6px_0_rgba(0,0,0,0.02)] transition-all duration-300 ease-in-out hover:bg-surface-tertiary"
|
||||
>
|
||||
<div className="flex w-full justify-between">
|
||||
<div className="flex flex-row gap-2">
|
||||
<CategoryIcon category={category} className="icon-md" />
|
||||
<h3 className="break-word select-none text-balance text-sm font-semibold text-gray-800 dark:text-gray-200">
|
||||
<h3 className="break-word select-none text-balance text-sm font-semibold text-text-primary">
|
||||
{name}
|
||||
</h3>
|
||||
</div>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
<div className="ellipsis select-none text-balance text-sm text-gray-600 dark:text-gray-400">
|
||||
{snippet}
|
||||
</div>
|
||||
</div>
|
||||
<div className="ellipsis select-none text-balance text-sm text-text-secondary">{snippet}</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue