mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 12:13:30 +00:00
🔗 feat: Open Footer Site Links in a New Tab (#15019)
The footer's LibreChat site link navigated away from the chat in the same tab. Footer content links (default version link and custom footer markdown) now open in a new tab with noopener noreferrer. Privacy policy and terms of service links keep same-tab navigation, following the WCAG decision in #10997.
This commit is contained in:
parent
7569404a7c
commit
f1fbaeb6d8
2 changed files with 58 additions and 1 deletions
|
|
@ -63,7 +63,8 @@ function Footer({ className, startupConfig }: FooterProps) {
|
|||
<a
|
||||
className="text-text-secondary underline"
|
||||
href={href}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
56
client/src/components/Chat/__tests__/Footer.spec.tsx
Normal file
56
client/src/components/Chat/__tests__/Footer.spec.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import Footer from '../Footer';
|
||||
|
||||
jest.mock('react-gtm-module', () => ({
|
||||
__esModule: true,
|
||||
default: { initialize: jest.fn() },
|
||||
}));
|
||||
|
||||
jest.mock('~/data-provider', () => ({
|
||||
useGetStartupConfig: jest.fn(() => ({ data: undefined, isFetching: false, error: null })),
|
||||
}));
|
||||
|
||||
const mockTranslations: Record<string, string> = {
|
||||
com_ui_latest_footer: 'Every AI for Everyone.',
|
||||
com_ui_privacy_policy: 'Privacy policy',
|
||||
com_ui_terms_of_service: 'Terms of service',
|
||||
};
|
||||
|
||||
jest.mock('~/hooks', () => ({
|
||||
useLocalize: () => (key: string) => mockTranslations[key] ?? key,
|
||||
}));
|
||||
|
||||
describe('Footer', () => {
|
||||
test('opens the default LibreChat site link in a new tab', () => {
|
||||
render(<Footer startupConfig={null} />);
|
||||
const link = screen.getByRole('link', { name: /LibreChat/ });
|
||||
expect(link).toHaveAttribute('href', 'https://librechat.ai');
|
||||
expect(link).toHaveAttribute('target', '_blank');
|
||||
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
||||
});
|
||||
|
||||
test('opens custom footer markdown links in a new tab', () => {
|
||||
render(<Footer startupConfig={{ customFooter: '[Docs](https://example.com/docs)' }} />);
|
||||
const link = screen.getByRole('link', { name: 'Docs' });
|
||||
expect(link).toHaveAttribute('href', 'https://example.com/docs');
|
||||
expect(link).toHaveAttribute('target', '_blank');
|
||||
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
||||
});
|
||||
|
||||
test('keeps privacy policy and terms of service links in the same tab', () => {
|
||||
render(
|
||||
<Footer
|
||||
startupConfig={{
|
||||
interface: {
|
||||
privacyPolicy: { externalUrl: 'https://example.com/privacy' },
|
||||
termsOfService: { externalUrl: 'https://example.com/terms' },
|
||||
},
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole('link', { name: 'Privacy policy' })).not.toHaveAttribute('target');
|
||||
expect(screen.getByRole('link', { name: 'Terms of service' })).not.toHaveAttribute('target');
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue