feat: Enhance AuthorInfo component with link support and add ErrorElement for improved error handling

This commit is contained in:
alexsparkes
2026-02-07 13:48:31 +00:00
parent 2d7e1ad97a
commit f891a16350
4 changed files with 102 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
import { MdPerson, MdOpenInNew } from 'react-icons/md';
import { MdPerson } from 'react-icons/md';
import { HiMiniArrowUpRight } from 'react-icons/hi2';
import { Tooltip } from 'components/Elements';
import { useT } from 'contexts';
import QuoteButtons from './QuoteButtons';
@@ -39,7 +40,20 @@ export default function AuthorInfo({
{author ? (
<div className="author-content">
<span className="title">{author}</span>
{hasLink ? (
<a
href={authorlink}
className="author-name-link"
target="_blank"
rel="noopener noreferrer"
aria-label={t('widgets.quote.author_info_aria')}
>
<span className="title">{author}</span>
<HiMiniArrowUpRight className="author-arrow" />
</a>
) : (
<span className="title">{author}</span>
)}
{authorOccupation && authorOccupation !== 'Unknown' && (
<span className="subtitle">{authorOccupation}</span>
)}
@@ -52,19 +66,6 @@ export default function AuthorInfo({
)}
<div className="quote-buttons">
{hasLink && (
<Tooltip title={t('widgets.quote.link_tooltip')}>
<a
href={authorlink}
className="quoteAuthorLink"
target="_blank"
rel="noopener noreferrer"
aria-label={t('widgets.quote.author_info_aria')}
>
<MdOpenInNew />
</a>
</Tooltip>
)}
<QuoteButtons
onCopy={onCopy}
onFavourite={onFavourite}

View File

@@ -113,6 +113,29 @@ h1.quoteauthor {
}
}
.author-name-link {
display: flex;
align-items: center;
gap: 4px;
text-decoration: none;
color: inherit;
transition: opacity 0.2s ease;
cursor: pointer;
&:hover {
opacity: 0.8;
}
.author-arrow {
font-size: 1rem;
transition: transform 0.2s ease;
}
&:hover .author-arrow {
transform: translateX(3px);
}
}
.author-holder {
display: flex;
align-items: center;

View File

@@ -0,0 +1,61 @@
import { useRouteError } from 'react-router';
import { captureException } from '@sentry/react';
import variables from 'config/variables';
import { useState } from 'react';
/**
* Error element for React Router error boundaries
* Displays when a route throws an error or fails to load
*/
export default function ErrorElement() {
const error = useRouteError();
const [showReport, setShowReport] = useState(true);
console.error('Route error:', error);
const reportError = () => {
captureException(error);
setShowReport(false);
};
const title = variables.getMessage
? variables.getMessage('error_boundary.title')
: 'An error occurred';
const message = variables.getMessage
? variables.getMessage('error_boundary.message')
: 'Something went wrong. Please try refreshing the page.';
const reportButton = variables.getMessage
? variables.getMessage('error_boundary.report_button')
: 'Report Error';
const sentSuccessfully = variables.getMessage
? variables.getMessage('error_boundary.sent_successfully')
: 'Report sent successfully';
const supportDiscord = variables.getMessage
? variables.getMessage('error_boundary.support_discord')
: 'Get Support on Discord';
return (
<div className="criticalError">
<div className="criticalError-message">
<h1>{title}</h1>
<p>{message}</p>
{error?.message && (
<details style={{ marginTop: '1rem', opacity: 0.7 }}>
<summary>Error Details</summary>
<pre style={{ marginTop: '0.5rem', fontSize: '0.9em' }}>{error.message}</pre>
</details>
)}
<div className="criticalError-actions">
{showReport ? (
<button onClick={reportError}>{reportButton}</button>
) : (
<p>{sentSuccessfully}</p>
)}
<a href="https://discord.gg/zv8C9F8" target="_blank" rel="noreferrer">
{supportDiscord}
</a>
</div>
</div>
</div>
);
}

View File

@@ -1,6 +1,7 @@
import { lazy } from 'react';
import { Navigate } from 'react-router';
import App from '../App';
import ErrorElement from './ErrorElement';
// Lazy load tab components
const Settings = lazy(() => import('../features/misc/views/Settings'));
@@ -19,6 +20,7 @@ export const routes = [
{
path: '/',
element: <App />,
errorElement: <ErrorElement />,
children: [
{
index: true,