Files
gridpilot.gg/apps/website/components/errors/ErrorDetailsBlock.tsx
2026-01-19 01:24:07 +01:00

70 lines
2.0 KiB
TypeScript

'use client';
import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card';
import { Icon } from '@/ui/Icon';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/Box';
import { Stack } from '@/ui/Stack';
import { Accordion } from '@/ui/Accordion';
import { Copy } from 'lucide-react';
import React, { useState } from 'react';
interface ErrorDetailsBlockProps {
error: Error & { digest?: string };
}
/**
* ErrorDetailsBlock
*
* Semantic component for technical error details.
* Follows "Precision Racing Minimal" theme.
*/
export function ErrorDetailsBlock({ error }: ErrorDetailsBlockProps) {
const [copied, setCopied] = useState(false);
const copyError = async () => {
const details = {
message: error.message,
digest: error.digest,
stack: error.stack,
url: typeof window !== 'undefined' ? window.location.href : 'unknown',
timestamp: new Date().toISOString(),
};
try {
await navigator.clipboard.writeText(JSON.stringify(details, null, 2));
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
// Silent fail
}
};
return (
<Box width="100%" marginTop={6} paddingTop={6} borderTop="1px solid var(--ui-color-border-muted)">
<Accordion title="Technical Logs">
<Stack gap={4}>
<Card variant="outline">
<Text font="mono" size="xs" variant="low" block leading="relaxed" style={{ maxHeight: '12rem', overflow: 'auto' }}>
{error.stack || 'No stack trace available'}
{error.digest && `\n\nDigest: ${error.digest}`}
</Text>
</Card>
<Box display="flex" justifyContent="end">
<Button
variant="secondary"
size="sm"
onClick={copyError}
icon={<Icon icon={Copy} size={3} intent="low" />}
>
{copied ? 'Copied!' : 'Copy Details'}
</Button>
</Box>
</Stack>
</Accordion>
</Box>
);
}