import React from 'react' import { AlertOctagon, RefreshCw } from 'lucide-react' interface Props { children: React.ReactNode } interface State { error: Error | null info: React.ErrorInfo | null } /** * Top-level error boundary. Catches any render-time exception in the * React tree and renders a recoverable error card instead of a blank * white screen. Component-level errors below this point should still * use local try/catch + toast for inline failures (network etc.). */ export default class ErrorBoundary extends React.Component { constructor(props: Props) { super(props) this.state = { error: null, info: null } } static getDerivedStateFromError(error: Error): Partial { return { error } } componentDidCatch(error: Error, info: React.ErrorInfo): void { // Keep the structured info around for the "Copy details" button. We // intentionally do NOT post this anywhere — the app is local-first. this.setState({ error, info }) console.error('[ErrorBoundary]', error, info?.componentStack) } reset = (): void => { this.setState({ error: null, info: null }) } reload = (): void => { window.location.reload() } copyDetails = async (): Promise => { const { error, info } = this.state if (!error) return const text = [ `Error: ${error.name}: ${error.message}`, '', 'Stack:', error.stack ?? '(no stack)', '', 'Component stack:', info?.componentStack ?? '(no component stack)', '', `URL: ${window.location.href}`, `User agent: ${navigator.userAgent}`, ].join('\n') try { await navigator.clipboard.writeText(text) } catch { /* ignore — clipboard may be unavailable in non-secure contexts */ } } render(): React.ReactNode { if (!this.state.error) return this.props.children const { error } = this.state return (

Something broke while rendering this page

The app caught the error so the rest of TextBro keeps running. You can try going back, reloading, or copying the details to report the bug.

              {error.name}: {error.message}
            
) } }