cleanup: code formatting and improve readability across multiple components

This commit is contained in:
Marco Beretta 2025-05-31 20:48:23 +02:00
parent 4808c5be48
commit a06e999dd6
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
144 changed files with 608 additions and 648 deletions

View file

@ -1,9 +1,9 @@
import { defaultNS, resources } from '~/locales/i18n';
declare module 'i18next' {
interface CustomTypeOptions {
defaultNS: typeof defaultNS;
resources: typeof resources.en;
strictKeyChecks: true
}
}
interface CustomTypeOptions {
defaultNS: typeof defaultNS;
resources: typeof resources.en;
strictKeyChecks: true;
}
}

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export type RenderProp<
P = React.HTMLAttributes<any> & {
ref?: React.Ref<any>;

View file

@ -9,16 +9,17 @@ export function useDebounceCodeBlock() {
const setCodeBlocks = useSetRecoilState(codeBlocksState);
const setCodeBlockIds = useSetRecoilState(codeBlockIdsState);
const updateCodeBlock = useCallback((codeBlock: CodeBlock) => {
console.log('Updating code block:', codeBlock);
setCodeBlocks((prev) => ({
...prev,
[codeBlock.id]: codeBlock,
}));
setCodeBlockIds((prev) =>
prev.includes(codeBlock.id) ? prev : [...prev, codeBlock.id],
);
}, [setCodeBlocks, setCodeBlockIds]);
const updateCodeBlock = useCallback(
(codeBlock: CodeBlock) => {
console.log('Updating code block:', codeBlock);
setCodeBlocks((prev) => ({
...prev,
[codeBlock.id]: codeBlock,
}));
setCodeBlockIds((prev) => (prev.includes(codeBlock.id) ? prev : [...prev, codeBlock.id]));
},
[setCodeBlocks, setCodeBlockIds],
);
const debouncedUpdateCodeBlock = useCallback(
debounce((codeBlock: CodeBlock) => {

View file

@ -87,8 +87,8 @@ function AuthLayout({
{children}
{!pathname.includes('2fa') &&
(pathname.includes('login') || pathname.includes('register')) && (
<SocialLoginRender startupConfig={startupConfig} />
)}
<SocialLoginRender startupConfig={startupConfig} />
)}
</div>
</div>
<Footer startupConfig={startupConfig} />

View file

@ -105,23 +105,12 @@ function RequestPasswordReset() {
},
})}
aria-invalid={!!errors.email}
className="
peer w-full rounded-lg border border-gray-300 bg-transparent px-4 py-3
text-base text-gray-900 placeholder-transparent transition-all
focus:border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/20
dark:border-gray-700 dark:text-white dark:focus:border-green-500
"
className="peer w-full rounded-lg border border-gray-300 bg-transparent px-4 py-3 text-base text-gray-900 placeholder-transparent transition-all focus:border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/20 dark:border-gray-700 dark:text-white dark:focus:border-green-500"
placeholder="email@example.com"
/>
<label
htmlFor="email"
className="
absolute -top-2 left-2 z-10 bg-white px-2 text-sm text-gray-600
transition-all peer-placeholder-shown:top-3 peer-placeholder-shown:text-base
peer-placeholder-shown:text-gray-500 peer-focus:-top-2 peer-focus:text-sm
peer-focus:text-green-600 dark:bg-gray-900 dark:text-gray-400
dark:peer-focus:text-green-500
"
className="absolute -top-2 left-2 z-10 bg-white px-2 text-sm text-gray-600 transition-all peer-placeholder-shown:top-3 peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-500 peer-focus:-top-2 peer-focus:text-sm peer-focus:text-green-600 dark:bg-gray-900 dark:text-gray-400 dark:peer-focus:text-green-500"
>
{localize('com_auth_email_address')}
</label>
@ -136,12 +125,7 @@ function RequestPasswordReset() {
<button
type="submit"
disabled={!!errors.email}
className="
w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white
transition-colors hover:bg-green-700 focus:outline-none focus:ring-2
focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50
disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700
"
className="w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50 disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700"
>
{localize('com_auth_continue')}
</button>

View file

@ -89,20 +89,12 @@ function ResetPassword() {
},
})}
aria-invalid={!!errors.password}
className="
webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light
bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none
"
className="webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none"
placeholder=" "
/>
<label
htmlFor="password"
className="
absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200
peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100
peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500
rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4
"
className="absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200 peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100 peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500 rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4"
>
{localize('com_auth_password')}
</label>
@ -124,20 +116,12 @@ function ResetPassword() {
validate: (value) => value === password || localize('com_auth_password_not_match'),
})}
aria-invalid={!!errors.confirm_password}
className="
webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light
bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none
"
className="webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none"
placeholder=" "
/>
<label
htmlFor="confirm_password"
className="
absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200
peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100
peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500
rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4
"
className="absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200 peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100 peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-500 rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4"
>
{localize('com_auth_password_confirm')}
</label>
@ -163,12 +147,7 @@ function ResetPassword() {
disabled={!!errors.password || !!errors.confirm_password}
type="submit"
aria-label={localize('com_auth_submit_registration')}
className="
w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white
transition-colors hover:bg-green-700 focus:outline-none focus:ring-2
focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50
disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700
"
className="w-full rounded-2xl bg-green-600 px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50 disabled:hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-700"
>
{localize('com_auth_continue')}
</button>

View file

@ -156,7 +156,6 @@ test('renders registration form', () => {
);
});
// eslint-disable-next-line jest/no-commented-out-tests
// test('calls registerUser.mutate on registration', async () => {
// const mutate = jest.fn();
// const { getByTestId, getByRole, history } = setup({

View file

@ -1,12 +1,6 @@
export default function DragDropOverlay() {
return (
<div
className="bg-surface-primary/85 fixed inset-0 z-[9999] flex flex-col items-center justify-center
gap-2 text-text-primary
backdrop-blur-[4px] transition-all duration-200
ease-in-out animate-in fade-in
zoom-in-95 hover:backdrop-blur-sm"
>
<div className="bg-surface-primary/85 fixed inset-0 z-[9999] flex flex-col items-center justify-center gap-2 text-text-primary backdrop-blur-[4px] transition-all duration-200 ease-in-out animate-in fade-in zoom-in-95 hover:backdrop-blur-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 132 108"
@ -55,8 +49,8 @@ export default function DragDropOverlay() {
</clipPath>
</defs>
</svg>
<h3>Add anything</h3>
<h4>Drop any file here to add it to the conversation</h4>
<h3>{localize('com_ui_add_anything')}</h3>
<h4>{localize('com_ui_add_anything_description')}</h4>
</div>
);
}

View file

@ -93,9 +93,9 @@ const ImagePreview = ({
const style: styleProps = imageUrl
? {
...baseStyle,
backgroundImage: `url(${imageUrl})`,
}
...baseStyle,
backgroundImage: `url(${imageUrl})`,
}
: baseStyle;
if (typeof style.backgroundImage !== 'string' || style.backgroundImage.length === 0) {

View file

@ -39,7 +39,7 @@ export default function StreamAudio({ index = 0 }) {
const { pauseGlobalAudio } = usePauseGlobalAudio();
const { conversationId: paramId } = useParams();
const queryParam = paramId === 'new' ? paramId : latestMessage?.conversationId ?? paramId ?? '';
const queryParam = paramId === 'new' ? paramId : (latestMessage?.conversationId ?? paramId ?? '');
const queryClient = useQueryClient();
const getMessages = useCallback(

View file

@ -102,12 +102,12 @@ export function EndpointItem({ endpoint }: EndpointItemProps) {
if (endpoint.hasModels) {
const filteredModels = searchValue
? filterModels(
endpoint,
(endpoint.models || []).map((model) => model.name),
searchValue,
agentsMap,
assistantsMap,
)
endpoint,
(endpoint.models || []).map((model) => model.name),
searchValue,
agentsMap,
assistantsMap,
)
: null;
const placeholder =
isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)

View file

@ -45,10 +45,10 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
</div>
) : (isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)) &&
endpoint.icon ? (
<div className="flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
{endpoint.icon}
</div>
) : null}
<div className="flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
{endpoint.icon}
</div>
) : null}
<span>{modelName}</span>
</div>
{isGlobal && <EarthIcon className="ml-auto size-4 text-green-400" />}

View file

@ -102,22 +102,22 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
const filteredModels = endpoint.label.toLowerCase().includes(lowerQuery)
? endpoint.models
: endpoint.models.filter((model) => {
let modelName = model.name;
if (
isAgentsEndpoint(endpoint.value) &&
let modelName = model.name;
if (
isAgentsEndpoint(endpoint.value) &&
endpoint.agentNames &&
endpoint.agentNames[model.name]
) {
modelName = endpoint.agentNames[model.name];
} else if (
isAssistantsEndpoint(endpoint.value) &&
) {
modelName = endpoint.agentNames[model.name];
} else if (
isAssistantsEndpoint(endpoint.value) &&
endpoint.assistantNames &&
endpoint.assistantNames[model.name]
) {
modelName = endpoint.assistantNames[model.name];
}
return modelName.toLowerCase().includes(lowerQuery);
});
) {
modelName = endpoint.assistantNames[model.name];
}
return modelName.toLowerCase().includes(lowerQuery);
});
if (!filteredModels.length) {
return null; // skip if no models match

View file

@ -33,7 +33,7 @@ export const data: TModelSpec[] = [
iconURL: EModelEndpoint.openAI, // Allow using project-included icons
preset: {
chatGptLabel: 'Vision Helper',
greeting: 'What\'s up!!',
greeting: "What's up!!",
endpoint: EModelEndpoint.openAI,
model: 'gpt-4-turbo',
promptPrefix:

View file

@ -55,7 +55,7 @@ const MenuItem: FC<MenuItemProps> = ({
>
<div className="flex grow items-center justify-between gap-2">
<div>
<div className={cn('flex items-center gap-1 ')}>
<div className={cn('flex items-center gap-1')}>
{icon != null ? icon : null}
<div className={cn('truncate', textClassName)}>
{title}
@ -72,7 +72,7 @@ const MenuItem: FC<MenuItemProps> = ({
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="icon-md block "
className="icon-md block"
>
<path
fillRule="evenodd"

View file

@ -117,9 +117,9 @@ const EditTextPart = ({
messages.map((msg) =>
msg.messageId === messageId
? {
...msg,
content: updatedContent,
}
...msg,
content: updatedContent,
}
: msg,
),
);

View file

@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil';
import { useMessageProcess } from '~/hooks';
import type { TMessageProps } from '~/common';
import MessageRender from './ui/MessageRender';
// eslint-disable-next-line import/no-cycle
import MultiMessage from './MultiMessage';
import { cn } from '~/utils';
import store from '~/store';
@ -73,7 +73,7 @@ export default function Message(props: TMessageProps) {
</div>
</div>
) : (
<div className="m-auto justify-center p-4 py-2 md:gap-6 ">
<div className="m-auto justify-center p-4 py-2 md:gap-6">
<MessageRender {...props} />
</div>
)}

View file

@ -42,7 +42,7 @@ export function TemporaryChat() {
render={
<button
onClick={handleBadgeToggle}
aria-label={localize(temporaryBadge.label)}
aria-label={localize(temporaryBadge.label)}
className={cn(
'inline-flex size-10 flex-shrink-0 items-center justify-center rounded-xl border border-border-light text-text-primary transition-all ease-in-out hover:bg-surface-tertiary',
isTemporary

View file

@ -48,15 +48,15 @@ const UserAvatar = memo(({ size, user, avatarSrc, username, className }: UserAva
>
{(!(user?.avatar ?? '') && (!(user?.username ?? '') || user?.username.trim() === '')) ||
imageError ? (
renderDefaultAvatar()
) : (
<img
className="rounded-full"
src={(user?.avatar ?? '') || avatarSrc}
alt="avatar"
onError={handleImageError}
/>
)}
renderDefaultAvatar()
) : (
<img
className="rounded-full"
src={(user?.avatar ?? '') || avatarSrc}
alt="avatar"
onError={handleImageError}
/>
)}
</div>
);
});

View file

@ -23,7 +23,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) =>
});
const toastTitle =
_preset.title ?? '' ? `\`${_preset.title}\`` : localize('com_endpoint_preset_title');
(_preset.title ?? '') ? `\`${_preset.title}\`` : localize('com_endpoint_preset_title');
createPresetMutation.mutate(_preset, {
onSuccess: () => {
@ -76,7 +76,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) =>
aria-label={localize('com_endpoint_preset_name')}
className={cn(
defaultTextProps,
'flex h-10 max-h-10 w-full resize-none border-border-medium px-3 py-2 ',
'flex h-10 max-h-10 w-full resize-none border-border-medium px-3 py-2',
removeFocusOutlines,
)}
/>

View file

@ -109,7 +109,7 @@ export default function Settings({
placeholder={localize('com_endpoint_openai_prompt_prefix_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2 ',
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
)}
/>
</div>
@ -160,6 +160,7 @@ export default function Settings({
<div className="flex justify-between">
<Label htmlFor="top-p-int" className="text-left text-sm font-medium">
{localize('com_endpoint_top_p')}{' '}
{/* eslint-disable-next-line i18next/no-literal-string */}
<small className="opacity-40">({localize('com_endpoint_default')}: 1)</small>
</Label>
<InputNumber
@ -198,7 +199,8 @@ export default function Settings({
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="freq-penalty-int" className="text-left text-sm font-medium">
{localize('com_endpoint_frequency_penalty')}{' '}
{localize('com_endpoint_frequency_penalty')}
{/* eslint-disable-next-line i18next/no-literal-string */}
<small className="opacity-40">({localize('com_endpoint_default')}: 0)</small>
</Label>
<InputNumber
@ -238,6 +240,7 @@ export default function Settings({
<div className="flex justify-between">
<Label htmlFor="pres-penalty-int" className="text-left text-sm font-medium">
{localize('com_endpoint_presence_penalty')}{' '}
{/* eslint-disable-next-line i18next/no-literal-string */}
<small className="opacity-40">({localize('com_endpoint_default')}: 0)</small>
</Label>
<InputNumber

View file

@ -161,7 +161,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
placeholder={localize('com_endpoint_prompt_prefix_assistants_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2 ',
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2',
)}
/>
</div>
@ -178,7 +178,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
placeholder={localize('com_endpoint_instructions_assistants_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2 ',
'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2',
)}
/>
</div>

View file

@ -42,7 +42,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }:
placeholder="Set example input. Example is ignored if empty."
className={cn(
defaultTextProps,
'flex max-h-[138px] min-h-[75px] w-full resize-none px-3 py-2 ',
'flex max-h-[138px] min-h-[75px] w-full resize-none px-3 py-2',
)}
/>
</div>
@ -67,7 +67,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }:
placeholder={'Set example output. Example is ignored if empty.'}
className={cn(
defaultTextProps,
'flex max-h-[300px] min-h-[75px] w-full resize-none px-3 py-2 ',
'flex max-h-[300px] min-h-[75px] w-full resize-none px-3 py-2',
)}
/>
</div>

View file

@ -94,7 +94,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
placeholder={localize('com_endpoint_prompt_prefix_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2 ',
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
)}
/>
</div>
@ -221,7 +221,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
<Label htmlFor="top-k-int" className="text-left text-sm font-medium">
{localize('com_endpoint_top_k')}{' '}
<small className="opacity-40">
({localize('com_endpoint_default_with_num',{ 0: google.topK.default + '' })})
({localize('com_endpoint_default_with_num', { 0: google.topK.default + '' })})
</small>
</Label>
<InputNumber
@ -261,7 +261,11 @@ export default function Settings({ conversation, setOption, models, readonly }:
<Label htmlFor="max-tokens-int" className="text-left text-sm font-medium">
{localize('com_endpoint_max_output_tokens')}{' '}
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: google.maxOutputTokens.default + '' })})
(
{localize('com_endpoint_default_with_num', {
0: google.maxOutputTokens.default + '',
})}
)
</small>
</Label>
<InputNumber

View file

@ -165,7 +165,7 @@ export default function Settings({
)}
className={cn(
defaultTextProps,
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2 ',
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
)}
/>
</div>

View file

@ -8,7 +8,7 @@ export default function Continue({ onClick }: TGenButtonProps) {
return (
<Button type="continue" onClick={onClick}>
<ContinueIcon className="text-gray-600/90 dark:text-gray-400 " />
<ContinueIcon className="text-gray-600/90 dark:text-gray-400" />
{localize('com_ui_continue')}
</Button>
);

View file

@ -8,7 +8,7 @@ export default function Stop({ onClick }: TGenButtonProps) {
return (
<Button type="stop" onClick={onClick}>
<StopGeneratingIcon className="text-gray-600/90 dark:text-gray-400 " />
<StopGeneratingIcon className="text-gray-600/90 dark:text-gray-400" />
{localize('com_ui_stop')}
</Button>
);

View file

@ -171,8 +171,8 @@ const SetKeyDialog = ({
{expiryTime === 'never'
? localize('com_endpoint_config_key_never_expires')
: `${localize('com_endpoint_config_key_encryption')} ${new Date(
expiryTime ?? 0,
).toLocaleString()}`}
expiryTime ?? 0,
).toLocaleString()}`}
</small>
<Dropdown
label="Expires "

View file

@ -66,7 +66,7 @@ const Plugin: React.FC<PluginProps> = ({ plugin }) => {
if (!plugin.loading && latestPlugin === 'self reflection') {
return 'Finished';
} else if (latestPlugin === 'self reflection') {
return 'I\'m thinking...';
return "I'm thinking...";
} else {
return (
<>
@ -112,9 +112,7 @@ const Plugin: React.FC<PluginProps> = ({ plugin }) => {
/>
{plugin.outputs && plugin.outputs.length > 0 && (
<CodeBlock
lang={
latestPlugin ? `RESPONSE FROM ${latestPlugin.toUpperCase()}` : 'RESPONSE'
}
lang={latestPlugin ? `RESPONSE FROM ${latestPlugin.toUpperCase()}` : 'RESPONSE'}
codeChildren={formatJSON(plugin.outputs ?? '')}
plugin={true}
classProp="max-h-[450px]"

View file

@ -1,7 +1,7 @@
import React from 'react';
import { useMessageProcess } from '~/hooks';
import type { TMessageProps } from '~/common';
// eslint-disable-next-line import/no-cycle
import MultiMessage from '~/components/Chat/Messages/MultiMessage';
import ContentRender from './ContentRender';
@ -64,7 +64,7 @@ export default function MessageContent(props: TMessageProps) {
</div>
</div>
) : (
<div className="m-auto justify-center p-4 py-2 md:gap-6 ">
<div className="m-auto justify-center p-4 py-2 md:gap-6">
<ContentRender {...props} />
</div>
)}

View file

@ -35,7 +35,7 @@ export default function NavToggle({
className,
'-translate-y-1/2 transition-transform',
navVisible ? 'rotate-0' : 'rotate-180',
navVisible && translateX ? 'translate-x-[260px]' : 'translate-x-0 ',
navVisible && translateX ? 'translate-x-[260px]' : 'translate-x-0',
)}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}

View file

@ -87,11 +87,11 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
},
...(startupConfig?.balance?.enabled
? [
{
value: SettingsTabValues.BALANCE,
{
value: SettingsTabValues.BALANCE,
icon: <DollarSign size={18} />,
label: 'com_nav_setting_balance' as TranslationKeys,
},
label: 'com_nav_setting_balance' as TranslationKeys,
},
]
: ([] as { value: SettingsTabValues; icon: React.JSX.Element; label: TranslationKeys }[])),
{

View file

@ -15,7 +15,9 @@ export default function DecibelSelector() {
<div className="flex items-center justify-between">
<div>{localize('com_nav_db_sensitivity')}</div>
<div className="w-2" />
<small className="opacity-40">({localize('com_endpoint_default_with_num', { 0: '-45' })})</small>
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: '-45' })})
</small>
</div>
<div className="flex items-center justify-between">
<Slider

View file

@ -14,9 +14,9 @@ const EngineSTTDropdown: React.FC<EngineSTTDropdownProps> = ({ external }) => {
const endpointOptions = external
? [
{ value: 'browser', label: localize('com_nav_browser') },
{ value: 'external', label: localize('com_nav_external') },
]
{ value: 'browser', label: localize('com_nav_browser') },
{ value: 'external', label: localize('com_nav_external') },
]
: [{ value: 'browser', label: localize('com_nav_browser') }];
const handleSelect = (value: string) => {

View file

@ -14,9 +14,9 @@ const EngineTTSDropdown: React.FC<EngineTTSDropdownProps> = ({ external }) => {
const endpointOptions = external
? [
{ value: 'browser', label: localize('com_nav_browser') },
{ value: 'external', label: localize('com_nav_external') },
]
{ value: 'browser', label: localize('com_nav_browser') },
{ value: 'external', label: localize('com_nav_external') },
]
: [{ value: 'browser', label: localize('com_nav_browser') }];
const handleSelect = (value: string) => {

View file

@ -15,7 +15,9 @@ export default function DecibelSelector() {
<div className="flex items-center justify-between">
<div>{localize('com_nav_playback_rate')}</div>
<div className="w-2" />
<small className="opacity-40">({localize('com_endpoint_default_with_num', { 0: '1' })})</small>
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: '1' })})
</small>
</div>
<div className="flex items-center justify-between">
<Slider

View file

@ -187,8 +187,7 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
value={searchValue}
onChange={handleSearch}
placeholder={localize('com_nav_plugin_search')}
className="
text-token-text-primary flex rounded-md border border-border-heavy bg-surface-tertiary py-2 pl-10 pr-2"
className="text-token-text-primary flex rounded-md border border-border-heavy bg-surface-tertiary py-2 pl-10 pr-2"
/>
</div>
</div>

View file

@ -9,7 +9,7 @@ type TPluginTooltipProps = {
function PluginTooltip({ content, position }: TPluginTooltipProps) {
return (
<HoverCardPortal>
<HoverCardContent side={position} className="w-80 ">
<HoverCardContent side={position} className="w-80">
<div className="space-y-2">
<div className="text-sm text-gray-600 dark:text-gray-300">
<div dangerouslySetInnerHTML={{ __html: content }} />

View file

@ -44,11 +44,11 @@ export default function FilterPrompts({
const categoryOptions = categories
? [...categories]
: [
{
value: SystemCategories.NO_CATEGORY,
label: localize('com_ui_no_category'),
},
];
{
value: SystemCategories.NO_CATEGORY,
label: localize('com_ui_no_category'),
},
];
return [...baseOptions, ...categoryOptions];
}, [categories, localize]);

View file

@ -26,8 +26,7 @@ export default function ListCard({
<div
onClick={onClick}
onKeyDown={handleKeyDown}
className="relative my-2 flex w-full cursor-pointer flex-col gap-2 rounded-xl border border-border-light px-3 pb-4 pt-3 text-start
align-top text-[15px] shadow-sm transition-all duration-300 ease-in-out hover:bg-surface-tertiary hover:shadow-lg"
className="relative my-2 flex w-full cursor-pointer flex-col gap-2 rounded-xl border border-border-light px-3 pb-4 pt-3 text-start align-top text-[15px] shadow-sm transition-all duration-300 ease-in-out hover:bg-surface-tertiary hover:shadow-lg"
role="button"
tabIndex={0}
aria-labelledby={`card-title-${name}`}

View file

@ -287,18 +287,18 @@ const PromptForm = () => {
{editorMode === PromptsEditorMode.ADVANCED &&
(isLoadingPrompts
? Array.from({ length: 6 }).map((_, index: number) => (
<div key={index} className="my-2">
<Skeleton className="h-[72px] w-full" />
</div>
))
<div key={index} className="my-2">
<Skeleton className="h-[72px] w-full" />
</div>
))
: prompts.length > 0 && (
<PromptVersions
group={group}
prompts={prompts}
selectionIndex={selectionIndex}
setSelectionIndex={setSelectionIndex}
/>
))}
<PromptVersions
group={group}
prompts={prompts}
selectionIndex={selectionIndex}
setSelectionIndex={setSelectionIndex}
/>
))}
</div>
);

View file

@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { useRecoilState } from 'recoil';
import type { TMessage } from 'librechat-data-provider';
import type { TMessageProps } from '~/common';
// eslint-disable-next-line import/no-cycle
import Message from './Message';
import store from '~/store';

View file

@ -19,7 +19,7 @@ export default function ImageVision() {
{...field}
checked={field.value}
onCheckedChange={field.onChange}
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
value={field.value?.toString()}
/>
)}

View file

@ -135,10 +135,9 @@ export default function ShareAgent({
'btn btn-neutral border-token-border-light relative h-9 rounded-lg font-medium',
removeFocusOutlines,
)}
aria-label={localize(
'com_ui_share_var',
{ 0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent') },
)}
aria-label={localize('com_ui_share_var', {
0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'),
})}
type="button"
>
<div className="flex items-center justify-center gap-2 text-blue-500">
@ -148,10 +147,9 @@ export default function ShareAgent({
</OGDialogTrigger>
<OGDialogContent className="w-11/12 md:max-w-xl">
<OGDialogTitle>
{localize(
'com_ui_share_var',
{ 0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent') },
)}
{localize('com_ui_share_var', {
0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'),
})}
</OGDialogTitle>
<form
className="p-2"

View file

@ -44,7 +44,9 @@ const BookmarkTableRow: React.FC<BookmarkTableRowProps> = ({ row, moveRow, posit
accept: 'bookmark',
drop: handleDrop,
hover(item: DragItem) {
if (!ref.current || item.index === position) {return;}
if (!ref.current || item.index === position) {
return;
}
moveRow(item.index, position);
item.index = position;
},

View file

@ -33,9 +33,7 @@ export default function ActionsAuth({ disableOAuth }: { disableOAuth?: boolean }
</label>
</div>
<div className="border-token-border-medium flex rounded-lg border text-sm hover:cursor-pointer">
<div className="h-9 grow px-3 py-2">
{localize(getAuthLocalizationKey(type))}
</div>
<div className="h-9 grow px-3 py-2">{localize(getAuthLocalizationKey(type))}</div>
<div className="bg-token-border-medium w-px"></div>
<button type="button" color="neutral" className="flex items-center gap-2 px-3">
<svg

View file

@ -29,7 +29,7 @@ export default function Code({ version }: { version: number | string }) {
{...field}
checked={field.value}
onCheckedChange={field.onChange}
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
value={field.value.toString()}
/>
)}

View file

@ -19,7 +19,7 @@ export default function ImageVision() {
{...field}
checked={field.value}
onCheckedChange={field.onChange}
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
className="relative float-left mr-2 inline-flex h-4 w-4 cursor-pointer"
value={field.value.toString()}
/>
)}

View file

@ -62,7 +62,7 @@ function DynamicCheckbox({
htmlFor={`${settingKey}-dynamic-checkbox`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}:{' '}
@ -81,7 +81,11 @@ function DynamicCheckbox({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
description={
descriptionCode
? (localize(description as TranslationKeys) ?? description)
: description
}
side={ESide.Left}
/>
)}

View file

@ -85,7 +85,7 @@ function DynamicCombobox({
htmlFor={`${settingKey}-dynamic-combobox`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
@ -97,10 +97,14 @@ function DynamicCombobox({
<ControlCombobox
displayValue={selectedValue}
selectPlaceholder={
selectPlaceholderCode === true ? localize(selectPlaceholder as TranslationKeys) : selectPlaceholder
selectPlaceholderCode === true
? localize(selectPlaceholder as TranslationKeys)
: selectPlaceholder
}
searchPlaceholder={
searchPlaceholderCode === true ? localize(searchPlaceholder as TranslationKeys) : searchPlaceholder
searchPlaceholderCode === true
? localize(searchPlaceholder as TranslationKeys)
: searchPlaceholder
}
isCollapsed={isCollapsed}
ariaLabel={settingKey}
@ -112,7 +116,11 @@ function DynamicCombobox({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
description={
descriptionCode
? (localize(description as TranslationKeys) ?? description)
: description
}
side={ESide.Left}
/>
)}

View file

@ -78,7 +78,7 @@ function DynamicDropdown({
htmlFor={`${settingKey}-dynamic-dropdown`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
@ -96,12 +96,20 @@ function DynamicDropdown({
availableValues={options}
containerClassName="w-full"
id={`${settingKey}-dynamic-dropdown`}
placeholder={placeholderCode ? localize(placeholder as TranslationKeys) ?? placeholder : placeholder}
placeholder={
placeholderCode
? (localize(placeholder as TranslationKeys) ?? placeholder)
: placeholder
}
/>
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
description={
descriptionCode
? (localize(description as TranslationKeys) ?? description)
: description
}
side={ESide.Left}
/>
)}

View file

@ -60,20 +60,26 @@ function DynamicSlider({
const enumToNumeric = useMemo(() => {
if (isEnum && options) {
return options.reduce((acc, mapping, index) => {
acc[mapping] = index;
return acc;
}, {} as Record<string, number>);
return options.reduce(
(acc, mapping, index) => {
acc[mapping] = index;
return acc;
},
{} as Record<string, number>,
);
}
return {};
}, [isEnum, options]);
const valueToEnumOption = useMemo(() => {
if (isEnum && options) {
return options.reduce((acc, option, index) => {
acc[index] = option;
return acc;
}, {} as Record<number, string>);
return options.reduce(
(acc, option, index) => {
acc[index] = option;
return acc;
},
{} as Record<number, string>,
);
}
return {};
}, [isEnum, options]);
@ -117,7 +123,7 @@ function DynamicSlider({
htmlFor={`${settingKey}-dynamic-setting`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
@ -132,7 +138,7 @@ function DynamicSlider({
onChange={(value) => setInputValue(Number(value))}
max={range ? range.max : (options?.length ?? 0) - 1}
min={range ? range.min : 0}
step={range ? range.step ?? 1 : 1}
step={range ? (range.step ?? 1) : 1}
controls={false}
className={cn(
defaultTextProps,
@ -164,19 +170,23 @@ function DynamicSlider({
value={[
isEnum
? enumToNumeric[(selectedValue as number) ?? '']
: (inputValue as number) ?? (defaultValue as number),
: ((inputValue as number) ?? (defaultValue as number)),
]}
onValueChange={(value) => handleValueChange(value[0])}
onDoubleClick={() => setInputValue(defaultValue as string | number)}
max={max}
min={range ? range.min : 0}
step={range ? range.step ?? 1 : 1}
step={range ? (range.step ?? 1) : 1}
className="flex h-4 w-full"
/>
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
description={
descriptionCode
? (localize(description as TranslationKeys) ?? description)
: description
}
side={ESide.Left}
/>
)}

View file

@ -58,7 +58,7 @@ function DynamicTextarea({
htmlFor={`${settingKey}-dynamic-textarea`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
(
@ -75,7 +75,11 @@ function DynamicTextarea({
disabled={readonly}
value={inputValue ?? ''}
onChange={setInputValue}
placeholder={placeholderCode ? localize(placeholder as TranslationKeys) ?? placeholder : placeholder}
placeholder={
placeholderCode
? (localize(placeholder as TranslationKeys) ?? placeholder)
: placeholder
}
className={cn(
// TODO: configurable max height
'flex max-h-[138px] min-h-[100px] w-full resize-none rounded-lg bg-surface-secondary px-3 py-2 focus:outline-none',
@ -84,7 +88,11 @@ function DynamicTextarea({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
description={
descriptionCode
? (localize(description as TranslationKeys) ?? description)
: description
}
side={ESide.Left}
/>
)}

View file

@ -15,4 +15,4 @@ export default function AppleIcon() {
/>
</svg>
);
}
}

View file

@ -1,4 +1,3 @@
import { cn } from '~/utils/';
export default function AzureMinimalIcon({

View file

@ -28,7 +28,7 @@ const AccordionTrigger = React.forwardRef<
{...props}
>
{children}
<ChevronDownIcon className="text-muted-foreground h-4 w-4 shrink-0 transition-transform duration-200" />
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));

View file

@ -24,8 +24,7 @@ const AnimatedSearchInput = ({
<div className="absolute left-3 top-1/2 z-50 -translate-y-1/2">
<Search
className={cn(
`
h-4 w-4 transition-all duration-500 ease-in-out`,
`h-4 w-4 transition-all duration-500 ease-in-out`,
isSearching && hasValue ? 'text-blue-400' : 'text-gray-400',
)}
/>
@ -37,31 +36,17 @@ const AnimatedSearchInput = ({
value={value}
onChange={onChange}
placeholder={placeholder}
className={`
peer relative z-20 w-full rounded-lg bg-surface-secondary px-10
py-2 outline-none ring-0 backdrop-blur-sm transition-all
duration-500 ease-in-out placeholder:text-gray-400
focus:outline-none focus:ring-0
`}
className={`peer relative z-20 w-full rounded-lg bg-surface-secondary px-10 py-2 outline-none ring-0 backdrop-blur-sm transition-all duration-500 ease-in-out placeholder:text-gray-400 focus:outline-none focus:ring-0`}
/>
{/* Gradient overlay */}
<div
className={`
pointer-events-none absolute inset-0 z-20 rounded-lg
bg-gradient-to-r from-blue-500/20 via-purple-500/20 to-blue-500/20
transition-all duration-500 ease-in-out
${isSearching && hasValue ? 'opacity-100 blur-sm' : 'opacity-0 blur-none'}
`}
className={`pointer-events-none absolute inset-0 z-20 rounded-lg bg-gradient-to-r from-blue-500/20 via-purple-500/20 to-blue-500/20 transition-all duration-500 ease-in-out ${isSearching && hasValue ? 'opacity-100 blur-sm' : 'opacity-0 blur-none'} `}
/>
{/* Animated loading indicator */}
<div
className={`
absolute right-3 top-1/2 z-20 -translate-y-1/2
transition-all duration-500 ease-in-out
${isSearching && hasValue ? 'scale-100 opacity-100' : 'scale-0 opacity-0'}
`}
className={`absolute right-3 top-1/2 z-20 -translate-y-1/2 transition-all duration-500 ease-in-out ${isSearching && hasValue ? 'scale-100 opacity-100' : 'scale-0 opacity-0'} `}
>
<div className="relative h-2 w-2">
<div className="absolute inset-0 animate-ping rounded-full bg-blue-500/60" />
@ -73,36 +58,19 @@ const AnimatedSearchInput = ({
{/* Outer glow effect */}
<div
className={`
absolute -inset-8 -z-10
transition-all duration-700 ease-in-out
${isSearching && hasValue ? 'scale-105 opacity-100' : 'scale-100 opacity-0'}
`}
className={`absolute -inset-8 -z-10 transition-all duration-700 ease-in-out ${isSearching && hasValue ? 'scale-105 opacity-100' : 'scale-100 opacity-0'} `}
>
<div className="absolute inset-0">
<div
className={`
bg-gradient-radial absolute inset-0 from-blue-500/10 to-transparent
transition-opacity duration-700 ease-in-out
${isSearching && hasValue ? 'animate-pulse-slow opacity-100' : 'opacity-0'}
`}
className={`bg-gradient-radial absolute inset-0 from-blue-500/10 to-transparent transition-opacity duration-700 ease-in-out ${isSearching && hasValue ? 'animate-pulse-slow opacity-100' : 'opacity-0'} `}
/>
<div
className={`
absolute inset-0 bg-gradient-to-r from-purple-500/5 via-blue-500/5 to-purple-500/5
blur-xl transition-all duration-700 ease-in-out
${isSearching && hasValue ? 'animate-gradient-x opacity-100' : 'opacity-0'}
`}
className={`absolute inset-0 bg-gradient-to-r from-purple-500/5 via-blue-500/5 to-purple-500/5 blur-xl transition-all duration-700 ease-in-out ${isSearching && hasValue ? 'animate-gradient-x opacity-100' : 'opacity-0'} `}
/>
</div>
</div>
<div
className={`
absolute inset-0 -z-20 scale-100 bg-gradient-to-r from-blue-500/10
via-purple-500/10 to-blue-500/10 opacity-0 blur-xl
transition-all duration-500 ease-in-out
peer-focus:scale-105 peer-focus:opacity-100
`}
className={`absolute inset-0 -z-20 scale-100 bg-gradient-to-r from-blue-500/10 via-purple-500/10 to-blue-500/10 opacity-0 blur-xl transition-all duration-500 ease-in-out peer-focus:scale-105 peer-focus:opacity-100`}
/>
</div>
);

View file

@ -1,7 +1,7 @@
import * as React from 'react';
import { Slot } from '@radix-ui/react-slot';
import { ChevronRight, MoreHorizontal } from 'lucide-react';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
const Breadcrumb = React.forwardRef<
@ -17,7 +17,7 @@ const BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWi
<ol
ref={ref}
className={cn(
'text-muted-foreground flex flex-wrap items-center gap-1.5 break-words text-sm sm:gap-2.5',
'flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5',
className,
)}
{...props}
@ -44,7 +44,7 @@ const BreadcrumbLink = React.forwardRef<
return (
<Comp
ref={ref}
className={cn('hover:text-foreground transition-colors', className)}
className={cn('transition-colors hover:text-foreground', className)}
{...props}
/>
);
@ -58,7 +58,7 @@ const BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentPropsWit
role="link"
aria-disabled="true"
aria-current="page"
className={cn('text-foreground font-normal', className)}
className={cn('font-normal text-foreground', className)}
{...props}
/>
),
@ -77,18 +77,22 @@ const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentP
);
BreadcrumbSeparator.displayName = 'BreadcrumbSeparator';
const BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => (
<span
role="presentation"
aria-hidden="true"
className={cn('flex h-9 w-9 items-center justify-center', className)}
{...props}
>
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">More</span>
</span>
);
BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis';
const BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => {
const localize = useLocalize();
return (
<span
role="presentation"
aria-hidden="true"
className={cn('flex h-9 w-9 items-center justify-center', className)}
{...props}
>
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">{localize('com_ui_more')}</span>
</span>
);
};
BreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis';
export {
Breadcrumb,

View file

@ -81,7 +81,7 @@ export default function ComboboxComponent({
isCollapsed
? 'flex h-9 w-9 shrink-0 items-center justify-center p-0 [&>span]:w-auto [&>svg]:hidden'
: '',
'bg-white text-black hover:bg-gray-50 focus-visible:ring-2 focus-visible:ring-gray-500 dark:bg-gray-850 dark:text-white ',
'bg-white text-black hover:bg-gray-50 focus-visible:ring-2 focus-visible:ring-gray-500 dark:bg-gray-850 dark:text-white',
)}
>
<SelectValue placeholder={selectPlaceholder}>
@ -93,7 +93,7 @@ export default function ComboboxComponent({
style={{ userSelect: 'none' }}
>
{selectedValue
? displayValue ?? selectedValue
? (displayValue ?? selectedValue)
: selectPlaceholder && selectPlaceholder}
</span>
</SelectValue>
@ -140,7 +140,7 @@ export default function ComboboxComponent({
<RadixSelect.Item key={value} value={`${value ?? ''}`} asChild>
<ComboboxItem
className={cn(
'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'rounded-lg hover:bg-gray-100/50 hover:bg-gray-50 dark:text-white dark:hover:bg-gray-600',
)}
/** Hacky fix for radix-ui Android issue: https://github.com/radix-ui/primitives/issues/1658 */
@ -155,8 +155,8 @@ export default function ComboboxComponent({
</RadixSelect.ItemIndicator>
</span>
<RadixSelect.ItemText>
<div className="[&_svg]:text-foreground flex items-center justify-center gap-3 dark:text-white [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0">
<div className="assistant-item overflow-hidden rounded-full ">
<div className="flex items-center justify-center gap-3 dark:text-white [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0 [&_svg]:text-foreground">
<div className="assistant-item overflow-hidden rounded-full">
{icon && icon}
</div>
{label}

View file

@ -29,7 +29,7 @@ export function DataTableColumnHeader<TData, TValue>({
<div className={cn('flex items-center space-x-2', className)}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm" className="data-[state=open]:bg-accent -ml-3 h-8">
<Button variant="ghost" size="sm" className="-ml-3 h-8 data-[state=open]:bg-accent">
<span>{title}</span>
{column.getIsSorted() === 'desc' ? (
<ArrowDownIcon className="ml-2 h-4 w-4" />
@ -42,16 +42,16 @@ export function DataTableColumnHeader<TData, TValue>({
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="z-[1001]">
<DropdownMenuItem onClick={() => column.toggleSorting(false)}>
<ArrowUpIcon className="text-muted-foreground/70 mr-2 h-3.5 w-3.5" />
<ArrowUpIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
Asc
</DropdownMenuItem>
<DropdownMenuItem onClick={() => column.toggleSorting(true)}>
<ArrowDownIcon className="text-muted-foreground/70 mr-2 h-3.5 w-3.5" />
<ArrowDownIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
Desc
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
<EyeNoneIcon className="text-muted-foreground/70 mr-2 h-3.5 w-3.5" />
<EyeNoneIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
Hide
</DropdownMenuItem>
</DropdownMenuContent>

View file

@ -39,7 +39,7 @@ const Dropdown: FC<DropdownProps> = ({
typeof option === 'string' ? option : option?.value;
const getDisplay = (option?: string | Option) =>
typeof option === 'string' ? option : option?.label ?? option?.value;
typeof option === 'string' ? option : (option?.label ?? option?.value);
const isEqual = (a: string | Option, b: string | Option): boolean => getValue(a) === getValue(b);

View file

@ -92,7 +92,7 @@ const InputWithDropdown = React.forwardRef<HTMLInputElement, InputWithDropdownPr
/>
<button
type="button"
className="text-tertiary hover:text-secondary absolute inset-y-0 right-0 flex items-center rounded-md px-2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring-primary"
className="text-tertiary absolute inset-y-0 right-0 flex items-center rounded-md px-2 hover:text-secondary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring-primary"
onClick={() => setIsOpen(!isOpen)}
aria-label={isOpen ? 'Close dropdown' : 'Open dropdown'}
>
@ -127,7 +127,7 @@ const InputWithDropdown = React.forwardRef<HTMLInputElement, InputWithDropdownPr
'cursor-pointer rounded-md px-3 py-2',
'focus:bg-surface-tertiary focus:outline-none focus:ring-1 focus:ring-inset focus:ring-ring-primary',
index === highlightedIndex
? 'text-primary bg-surface-active'
? 'bg-surface-active text-primary'
: 'text-secondary hover:bg-surface-tertiary',
)}
onClick={() => handleSelect(option)}

View file

@ -53,7 +53,7 @@ export default function MultiSearch({
<button
className={cn(
'relative flex h-5 w-5 items-center justify-end rounded-md text-text-secondary-alt',
value?.length ?? 0 ? 'cursor-pointer opacity-100' : 'hidden',
(value?.length ?? 0) ? 'cursor-pointer opacity-100' : 'hidden',
)}
aria-label={'Clear search'}
onClick={clearSearch}
@ -63,7 +63,7 @@ export default function MultiSearch({
aria-hidden={'true'}
className={cn(
'text-text-secondary-alt',
value?.length ?? 0 ? 'cursor-pointer opacity-100' : 'opacity-0',
(value?.length ?? 0) ? 'cursor-pointer opacity-100' : 'opacity-0',
)}
/>
</button>

View file

@ -142,7 +142,7 @@ function MultiSelectDropDown({
viewBox="0 0 24 24"
strokeLinecap="round"
strokeLinejoin="round"
className="h-4 w-4 text-gray-400"
className="h-4 w-4 text-gray-400"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"

View file

@ -54,14 +54,14 @@ function MultiSelectPop({
<button
data-testid="select-dropdown-button"
className={cn(
'relative flex flex-col rounded-md border border-black/10 bg-white py-2 pl-3 pr-10 text-left focus:outline-none focus:ring-0 focus:ring-offset-0 dark:border-gray-700 dark:bg-gray-800 dark:bg-gray-800 sm:text-sm',
'relative flex flex-col rounded-md border border-black/10 bg-white py-2 pl-3 pr-10 text-left focus:outline-none focus:ring-0 focus:ring-offset-0 dark:border-gray-700 dark:bg-gray-800 sm:text-sm',
'pointer-cursor font-normal',
'hover:bg-gray-50 radix-state-open:bg-gray-50 dark:hover:bg-gray-700 dark:radix-state-open:bg-gray-700',
)}
>
{' '}
{showLabel && (
<label className="block text-xs text-gray-700 dark:text-gray-500 ">{title}</label>
<label className="block text-xs text-gray-700 dark:text-gray-500">{title}</label>
)}
<span className="inline-flex" id={excludeIds[2]}>
<span
@ -73,7 +73,7 @@ function MultiSelectPop({
{/* {!showLabel && title.length > 0 && (
<span className="text-xs text-gray-700 dark:text-gray-500">{title}:</span>
)} */}
<span className="flex items-center gap-1 ">
<span className="flex items-center gap-1">
<div className="flex gap-1">
{value.length === 0 && 'None selected'}
{value.map((v, i) => (
@ -98,7 +98,7 @@ function MultiSelectPop({
viewBox="0 0 24 24"
strokeLinecap="round"
strokeLinejoin="round"
className="h-4 w-4 text-gray-400"
className="h-4 w-4 text-gray-400"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"

View file

@ -6,7 +6,7 @@ export default function Prompt({ title, prompt }: { title: string; prompt: strin
return (
<div
// onclick="selectPromptTemplate(0)"
className="flex w-full flex-col gap-2 rounded-md bg-gray-50 p-4 text-left hover:bg-gray-200 dark:bg-white/5 "
className="flex w-full flex-col gap-2 rounded-md bg-gray-50 p-4 text-left hover:bg-gray-200 dark:bg-white/5"
>
<h2 className="m-auto flex items-center gap-3 text-lg font-normal md:flex-col md:gap-2">
{title}

View file

@ -24,13 +24,13 @@ const ResizableHandle = ({
}) => (
<ResizablePrimitive.PanelResizeHandle
className={cn(
'bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
className,
)}
{...props}
>
{withHandle && (
<div className="bg-border z-10 flex h-4 w-3 items-center justify-center rounded-sm border">
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
<GripVertical className="h-2.5 w-2.5" />
</div>
)}
@ -46,13 +46,13 @@ const ResizableHandleAlt = ({
}) => (
<ResizablePrimitive.PanelResizeHandle
className={cn(
'bg-border focus-visible:ring-ring group relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
'group relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
className,
)}
{...props}
>
{withHandle && (
<div className="bg-border invisible z-10 flex h-4 w-3 items-center justify-center rounded-sm border group-hover:visible group-active:visible">
<div className="invisible z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border group-hover:visible group-active:visible">
<GripVertical className="h-2.5 w-2.5" />
</div>
)}

View file

@ -5,22 +5,22 @@ import { cn } from '~/utils';
const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & { onDoubleClick?: () => void }
>(({ className, onDoubleClick, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
'relative flex w-full cursor-pointer touch-none select-none items-center',
className,
)}
onDoubleClick={onDoubleClick}
{...props}
>
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
));
>(({ className, onDoubleClick, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
'relative flex w-full cursor-pointer touch-none select-none items-center',
className,
)}
onDoubleClick={onDoubleClick}
{...props}
>
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
));
Slider.displayName = SliderPrimitive.Root.displayName;
export { Slider };

View file

@ -32,7 +32,7 @@ const TableFooter = React.forwardRef<
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn('bg-muted/50 border-t font-medium [&>tr]:last:border-b-0', className)}
className={cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', className)}
{...props}
/>
));
@ -43,7 +43,7 @@ const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTML
<tr
ref={ref}
className={cn(
'hover:bg-muted/50 data-[state=selected]:bg-muted border-b border-border-light transition-colors',
'border-b border-border-light transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
className,
)}
{...props}
@ -59,7 +59,7 @@ const TableHead = React.forwardRef<
<th
ref={ref}
className={cn(
'text-muted-foreground h-12 px-4 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0',
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
className,
)}
{...props}
@ -83,7 +83,7 @@ const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption ref={ref} className={cn('text-muted-foreground mt-4 text-sm', className)} {...props} />
<caption ref={ref} className={cn('mt-4 text-sm text-muted-foreground', className)} {...props} />
));
TableCaption.displayName = 'TableCaption';

View file

@ -30,17 +30,17 @@ const TagPrimitiveRoot = React.forwardRef<HTMLDivElement, TagProps>(
{CancelButton
? CancelButton
: onRemove && (
<button
onClick={(e) => {
e.stopPropagation();
onRemove(e);
}}
className="rounded-full bg-green-600/50"
aria-label={`Remove ${label}`}
>
<X className="m-[1.5px] p-1" />
</button>
)}
<button
onClick={(e) => {
e.stopPropagation();
onRemove(e);
}}
className="rounded-full bg-green-600/50"
aria-label={`Remove ${label}`}
>
<X className="m-[1.5px] p-1" />
</button>
)}
</div>
),
);

View file

@ -73,7 +73,7 @@ const TermsAndConditionsModal = ({
main={
<section
// Motivation: This is a dialog, so its content should be focusable
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
tabIndex={0}
className="max-h-[60vh] overflow-y-auto p-4"
aria-label={localize('com_ui_terms_and_conditions')}

View file

@ -31,7 +31,7 @@ export default function useAddedHelpers({
store.messagesSiblingIdxFamily(latestMessage?.parentMessageId ?? null),
);
const queryParam = paramId === 'new' ? paramId : conversation?.conversationId ?? paramId ?? '';
const queryParam = paramId === 'new' ? paramId : (conversation?.conversationId ?? paramId ?? '');
const setMessages = useCallback(
(messages: TMessage[]) => {

View file

@ -42,7 +42,7 @@ function useDebouncedInput<T = unknown>({
typeof e !== 'object'
? e
: ((e as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>).target
.value as unknown as T);
.value as unknown as T);
if (numeric === true) {
newValue = Number(newValue) as unknown as T;
}

View file

@ -48,10 +48,11 @@ export default function useExportConversation({
const { conversationId: paramId } = useParams();
const getMessageTree = useCallback(() => {
const queryParam = paramId === 'new' ? paramId : conversation?.conversationId ?? paramId ?? '';
const queryParam =
paramId === 'new' ? paramId : (conversation?.conversationId ?? paramId ?? '');
const messages = queryClient.getQueryData<TMessage[]>([QueryKeys.messages, queryParam]) ?? [];
const dataTree = buildTree({ messages });
return dataTree?.length === 0 ? null : dataTree ?? null;
return dataTree?.length === 0 ? null : (dataTree ?? null);
}, [paramId, conversation?.conversationId, queryClient]);
const getMessageText = (message: TMessage | undefined, format = 'text') => {

View file

@ -113,11 +113,11 @@ export const useEndpoints = ({
hasModels,
icon: Icon
? React.createElement(Icon, {
size: 20,
className: 'text-text-primary shrink-0 icon-md',
iconURL: endpointIconURL,
endpoint: ep,
})
size: 20,
className: 'text-text-primary shrink-0 icon-md',
iconURL: endpointIconURL,
endpoint: ep,
})
: null,
};

View file

@ -33,9 +33,8 @@ export default function useContentHandler({ setMessages, getMessages }: TUseCont
const _messages = getMessages();
const messages =
_messages
?.filter((m) => m.messageId !== messageId)
.map((msg) => ({ ...msg, thread_id })) ?? [];
_messages?.filter((m) => m.messageId !== messageId).map((msg) => ({ ...msg, thread_id })) ??
[];
const userMessage = messages[messages.length - 1] as TMessage | undefined;
const { initialResponse } = submission;

View file

@ -46,4 +46,4 @@ describe('i18next translation tests', () => {
i18n.changeLanguage('fr');
expect(i18n.t('com_endpoint_default_with_num', { 0: 'Marie' })).toBe('par défaut : Marie');
});
});
});

View file

@ -948,5 +948,8 @@
"com_ui_yes": "Yes",
"com_ui_zoom": "Zoom",
"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.",
"com_ui_add_anything": "Add anything",
"com_ui_add_anything_description": "Drop any file here to add it to the conversation",
"com_ui_more": "More"
}

View file

@ -1,4 +1,3 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { EModelEndpoint, ImageDetail } from 'librechat-data-provider';
import type { ConversationData } from 'librechat-data-provider';
@ -98,7 +97,7 @@ export const convoData: ConversationData = {
promptPrefix: null,
resendFiles: false,
temperature: 1,
title: 'Write Einstein\'s Famous Equation in LaTeX',
title: "Write Einstein's Famous Equation in LaTeX",
top_p: 1,
updatedAt,
},

View file

@ -1,4 +1,3 @@
import { processLaTeX, preprocessLaTeX } from './latex';
describe('processLaTeX', () => {

View file

@ -40,4 +40,4 @@ jest.mock('react-i18next', () => {
init: jest.fn(),
},
};
});
});