mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
🎨 style: Unify Styles across Themes and Improve Accessibility (#7783)
* style: update button styles for improved hover effects and accessibility * style: enhance CustomMenuItem styling for improved visual feedback * style: improved accessibility and visual consistency * chore: add missing localization in ActionsPanel --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
c22d74d41e
commit
cd7dd576c1
9 changed files with 38 additions and 66 deletions
|
|
@ -159,7 +159,7 @@ export const CustomMenuItem = React.forwardRef<HTMLDivElement, CustomMenuItemPro
|
||||||
blurOnHoverEnd: false,
|
blurOnHoverEnd: false,
|
||||||
...props,
|
...props,
|
||||||
className: cn(
|
className: cn(
|
||||||
'flex cursor-default items-center gap-2 rounded-lg p-2 outline-none! scroll-m-1 scroll-mt-[calc(var(--combobox-height,0px)+var(--label-height,4px))] aria-disabled:opacity-25 border-l-2 border-transparent data-[active-item]:border-black data-[active-item]:rounded-l-none data-[active-item]:bg-black/[0.075] data-[active-item]:text-black dark:data-[active-item]:bg-white/10 dark:data-[active-item]:text-white dark:data-[active-item]:border-white sm:py-1 sm:text-sm min-w-0 w-full',
|
'relative flex cursor-default items-center gap-2 rounded-lg p-2 outline-none! scroll-m-1 scroll-mt-[calc(var(--combobox-height,0px)+var(--label-height,4px))] aria-disabled:opacity-25 data-[active-item]:bg-black/[0.075] data-[active-item]:text-black dark:data-[active-item]:bg-white/10 dark:data-[active-item]:text-white sm:py-1 sm:text-sm min-w-0 w-full before:absolute before:left-0 before:top-1 before:bottom-1 before:w-0.5 before:bg-transparent before:rounded-full data-[active-item]:before:bg-black dark:data-[active-item]:before:bg-white',
|
||||||
props.className,
|
props.className,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<TooltipAnchor
|
<TooltipAnchor
|
||||||
description={localize('com_ui_save')}
|
description={localize('com_ui_download')}
|
||||||
render={
|
render={
|
||||||
<Button onClick={() => downloadImage()} variant="ghost" className="h-10 w-10 p-0">
|
<Button onClick={() => downloadImage()} variant="ghost" className="h-10 w-10 p-0">
|
||||||
<ArrowDownToLine className="size-6" />
|
<ArrowDownToLine className="size-6" />
|
||||||
|
|
@ -108,7 +108,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
||||||
alt="Image"
|
alt="Image"
|
||||||
className="max-h-full max-w-full object-contain"
|
className="max-h-full max-w-full object-contain"
|
||||||
style={{
|
style={{
|
||||||
maxHeight: 'calc(100vh - 6rem)', // Account for header and padding
|
maxHeight: 'calc(100vh - 6rem)',
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -117,7 +117,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
||||||
|
|
||||||
{/* Side Panel */}
|
{/* Side Panel */}
|
||||||
<div
|
<div
|
||||||
className={`shadow-l-lg fixed right-0 top-0 z-20 h-full w-80 transform rounded-l-2xl border-l border-border-light bg-surface-secondary transition-transform duration-500 ease-in-out ${
|
className={`shadow-l-lg fixed right-0 top-0 z-20 h-full w-80 transform rounded-l-2xl border-l border-border-light bg-surface-primary transition-transform duration-500 ease-in-out ${
|
||||||
isPromptOpen ? 'translate-x-0' : 'translate-x-full'
|
isPromptOpen ? 'translate-x-0' : 'translate-x-full'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|
@ -132,7 +132,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Prompt Section */}
|
{/* Prompt Section */}
|
||||||
<div>
|
<div>
|
||||||
<h4 className="mb-2 text-sm font-medium text-text-secondary">
|
<h4 className="mb-2 text-sm font-medium text-text-primary">
|
||||||
{localize('com_ui_prompt')}
|
{localize('com_ui_prompt')}
|
||||||
</h4>
|
</h4>
|
||||||
<div className="rounded-md bg-surface-tertiary p-3">
|
<div className="rounded-md bg-surface-tertiary p-3">
|
||||||
|
|
@ -144,20 +144,18 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
||||||
|
|
||||||
{/* Generation Settings */}
|
{/* Generation Settings */}
|
||||||
<div>
|
<div>
|
||||||
<h4 className="mb-3 text-sm font-medium text-text-secondary">
|
<h4 className="mb-3 text-sm font-medium text-text-primary">
|
||||||
{localize('com_ui_generation_settings')}
|
{localize('com_ui_generation_settings')}
|
||||||
</h4>
|
</h4>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm text-text-secondary">{localize('com_ui_size')}:</span>
|
<span className="text-sm text-text-primary">{localize('com_ui_size')}:</span>
|
||||||
<span className="text-sm font-medium text-text-primary">
|
<span className="text-sm font-medium text-text-primary">
|
||||||
{args?.size || 'Unknown'}
|
{args?.size || 'Unknown'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm text-text-secondary">
|
<span className="text-sm text-text-primary">{localize('com_ui_quality')}:</span>
|
||||||
{localize('com_ui_quality')}:
|
|
||||||
</span>
|
|
||||||
<span
|
<span
|
||||||
className={`rounded px-2 py-1 text-xs font-medium capitalize ${
|
className={`rounded px-2 py-1 text-xs font-medium capitalize ${
|
||||||
args?.quality === 'high'
|
args?.quality === 'high'
|
||||||
|
|
@ -171,7 +169,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm text-text-secondary">
|
<span className="text-sm text-text-primary">
|
||||||
{localize('com_ui_file_size')}:
|
{localize('com_ui_file_size')}:
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm font-medium text-text-primary">
|
<span className="text-sm font-medium text-text-primary">
|
||||||
|
|
|
||||||
|
|
@ -178,17 +178,6 @@ export default function OpenAIImageGen({
|
||||||
<div className="relative my-2.5 flex size-5 shrink-0 items-center gap-2.5">
|
<div className="relative my-2.5 flex size-5 shrink-0 items-center gap-2.5">
|
||||||
<ProgressText progress={progress} error={cancelled} toolName={toolName} />
|
<ProgressText progress={progress} error={cancelled} toolName={toolName} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* {showInfo && hasInfo && (
|
|
||||||
<ToolCallInfo
|
|
||||||
key="tool-call-info"
|
|
||||||
input={args ?? ''}
|
|
||||||
output={output}
|
|
||||||
function_name={function_name}
|
|
||||||
pendingAuth={authDomain.length > 0 && !cancelled && initialProgress < 1}
|
|
||||||
/>
|
|
||||||
)} */}
|
|
||||||
|
|
||||||
<div className="relative mb-2 flex w-full justify-start">
|
<div className="relative mb-2 flex w-full justify-start">
|
||||||
<div ref={containerRef} className="w-full max-w-lg">
|
<div ref={containerRef} className="w-full max-w-lg">
|
||||||
{dimensions.width !== 'auto' && progress < 1 && (
|
{dimensions.width !== 'auto' && progress < 1 && (
|
||||||
|
|
|
||||||
|
|
@ -216,18 +216,12 @@ function FeedbackButtons({
|
||||||
|
|
||||||
function buttonClasses(isActive: boolean, isLast: boolean) {
|
function buttonClasses(isActive: boolean, isLast: boolean) {
|
||||||
return cn(
|
return cn(
|
||||||
'hover-button rounded-lg p-1.5',
|
'hover-button rounded-lg p-1.5 text-text-secondary-alt transition-colors duration-200',
|
||||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white',
|
'hover:text-text-primary hover:bg-surface-hover',
|
||||||
'hover:bg-gray-100 hover:text-gray-500',
|
'md:group-hover:visible md:group-focus-within:visible md:group-[.final-completion]:visible',
|
||||||
'data-[state=open]:active data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500',
|
!isLast && 'md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100',
|
||||||
isActive ? 'text-gray-500 dark:text-gray-200 font-bold' : 'dark:text-gray-400/70',
|
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
|
||||||
'dark:hover:bg-gray-700 dark:hover:text-gray-200',
|
isActive && 'active text-text-primary bg-surface-hover',
|
||||||
'data-[state=open]:dark:bg-gray-700 data-[state=open]:dark:text-gray-200',
|
|
||||||
'disabled:dark:hover:text-gray-400',
|
|
||||||
isLast
|
|
||||||
? ''
|
|
||||||
: 'data-[state=open]:opacity-100 md:opacity-0 md:group-focus-within:opacity-100 md:group-hover:opacity-100',
|
|
||||||
'md:group-focus-within:visible md:group-hover:visible md:group-[.final-completion]:visible',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,14 +211,12 @@ export default function Fork({
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttonStyle = cn(
|
const buttonStyle = cn(
|
||||||
'hover-button rounded-lg p-1.5',
|
'hover-button rounded-lg p-1.5 text-text-secondary-alt transition-colors duration-200',
|
||||||
'hover:bg-gray-100 hover:text-gray-500',
|
'hover:text-text-primary hover:bg-surface-hover',
|
||||||
'dark:text-gray-400/70 dark:hover:bg-gray-700 dark:hover:text-gray-200',
|
|
||||||
'disabled:dark:hover:text-gray-400',
|
|
||||||
'md:group-hover:visible md:group-focus-within:visible md:group-[.final-completion]:visible',
|
'md:group-hover:visible md:group-focus-within:visible md:group-[.final-completion]:visible',
|
||||||
!isLast && 'md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100',
|
!isLast && 'md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100',
|
||||||
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
|
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
|
||||||
isActive && 'active text-gray-700 dark:text-gray-200 bg-gray-100 bg-gray-700',
|
isActive && 'active text-text-primary bg-surface-hover',
|
||||||
);
|
);
|
||||||
|
|
||||||
const forkConvo = useForkConvoMutation({
|
const forkConvo = useForkConvoMutation({
|
||||||
|
|
|
||||||
|
|
@ -77,21 +77,13 @@ const HoverButton = memo(
|
||||||
className = '',
|
className = '',
|
||||||
}: HoverButtonProps) => {
|
}: HoverButtonProps) => {
|
||||||
const buttonStyle = cn(
|
const buttonStyle = cn(
|
||||||
'hover-button rounded-lg p-1.5',
|
'hover-button rounded-lg p-1.5 text-text-secondary-alt transition-colors duration-200',
|
||||||
|
'hover:text-text-primary hover:bg-surface-hover',
|
||||||
'hover:bg-gray-100 hover:text-gray-500',
|
|
||||||
|
|
||||||
'dark:text-gray-400/70 dark:hover:bg-gray-700 dark:hover:text-gray-200',
|
|
||||||
'disabled:dark:hover:text-gray-400',
|
|
||||||
|
|
||||||
'md:group-hover:visible md:group-focus-within:visible md:group-[.final-completion]:visible',
|
'md:group-hover:visible md:group-focus-within:visible md:group-[.final-completion]:visible',
|
||||||
!isLast && 'md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100',
|
!isLast && 'md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100',
|
||||||
!isVisible && 'opacity-0',
|
!isVisible && 'opacity-0',
|
||||||
|
|
||||||
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
|
'focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:outline-none',
|
||||||
|
isActive && isVisible && 'active text-text-primary bg-surface-hover',
|
||||||
isActive && isVisible && 'active text-gray-700 dark:text-gray-200 bg-gray-100 bg-gray-700',
|
|
||||||
|
|
||||||
className,
|
className,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ export default function ActionsPanel({
|
||||||
selectHandler: () => {
|
selectHandler: () => {
|
||||||
if (!agent_id) {
|
if (!agent_id) {
|
||||||
return showToast({
|
return showToast({
|
||||||
message: 'No agent_id found, is the agent created?',
|
message: localize('com_agents_no_agent_id_error'),
|
||||||
status: 'error',
|
status: 'error',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
"com_agents_missing_provider_model": "Please select a provider and model before creating an agent.",
|
"com_agents_missing_provider_model": "Please select a provider and model before creating an agent.",
|
||||||
"com_agents_name_placeholder": "Optional: The name of the agent",
|
"com_agents_name_placeholder": "Optional: The name of the agent",
|
||||||
"com_agents_no_access": "You don't have access to edit this agent.",
|
"com_agents_no_access": "You don't have access to edit this agent.",
|
||||||
|
"com_agents_no_agent_id_error": "No agent ID found. Please ensure the agent is created first.",
|
||||||
"com_agents_not_available": "Agent Not Available",
|
"com_agents_not_available": "Agent Not Available",
|
||||||
"com_agents_search_info": "When enabled, allows your agent to search the web for up-to-date information. Requires a valid API key.",
|
"com_agents_search_info": "When enabled, allows your agent to search the web for up-to-date information. Requires a valid API key.",
|
||||||
"com_agents_search_name": "Search agents by name",
|
"com_agents_search_name": "Search agents by name",
|
||||||
|
|
@ -970,4 +971,4 @@
|
||||||
"com_ui_zoom": "Zoom",
|
"com_ui_zoom": "Zoom",
|
||||||
"com_user_message": "You",
|
"com_user_message": "You",
|
||||||
"com_warning_resubmit_unsupported": "Resubmitting the AI message is not supported for this endpoint."
|
"com_warning_resubmit_unsupported": "Resubmitting the AI message is not supported for this endpoint."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2720,6 +2720,20 @@ html {
|
||||||
.shimmer {
|
.shimmer {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgb(33, 33, 33) 25%,
|
||||||
|
rgba(129, 130, 134, 0.18) 50%,
|
||||||
|
rgb(33, 33, 33) 75%
|
||||||
|
);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
animation: shimmer 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .shimmer {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
rgba(255, 255, 255, 0.8) 25%,
|
rgba(255, 255, 255, 0.8) 25%,
|
||||||
|
|
@ -2733,20 +2747,6 @@ html {
|
||||||
animation: shimmer 4s linear infinite;
|
animation: shimmer 4s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.dark) .shimmer {
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(255, 255, 255) 25%,
|
|
||||||
rgba(129, 130, 134, 0.18) 50%,
|
|
||||||
rgb(255, 255, 255) 75%
|
|
||||||
);
|
|
||||||
background-size: 200% 100%;
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
animation: shimmer 4s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-style-2 {
|
.custom-style-2 {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue