feat: F021 market intelligence & signal discovery
Signal domain types, mock data (8 signals), provider interface + MockupMarketIntelligenceProvider, marketIntelligenceService, TanStack Query hooks, 10 ops components (SignalInbox, MarketSignalCard, MarketSignalFilterBar, MarketSignalSkeleton, MarketSignalEmptyState, SignalConfidenceBadge, SourceReliabilityBadge, SensitivityWarningPanel, SignalConversionPanel, SignalEvidenceList), MarketIntelligence page wired into AppShell nav and App router. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { Box, Typography } from '@mui/material'
|
||||
import { Inbox, MousePointerClick, SearchX, AlertTriangle } from 'lucide-react'
|
||||
|
||||
type EmptyVariant = 'no-selection' | 'empty-inbox' | 'no-results' | 'not-found'
|
||||
|
||||
const VARIANTS: Record<EmptyVariant, { icon: typeof Inbox; title: string; subtitle: string }> = {
|
||||
'no-selection': {
|
||||
icon: MousePointerClick,
|
||||
title: 'Signal auswählen',
|
||||
subtitle: 'Wählen Sie ein Signal aus der Liste, um die Details anzuzeigen.',
|
||||
},
|
||||
'empty-inbox': {
|
||||
icon: Inbox,
|
||||
title: 'Keine Signale',
|
||||
subtitle: 'Es wurden noch keine Marktzeichen erkannt. Starten Sie eine Intelligence-Analyse.',
|
||||
},
|
||||
'no-results': {
|
||||
icon: SearchX,
|
||||
title: 'Keine Ergebnisse',
|
||||
subtitle: 'Keine Signale entsprechen den aktiven Filtern. Filter anpassen oder zurücksetzen.',
|
||||
},
|
||||
'not-found': {
|
||||
icon: AlertTriangle,
|
||||
title: 'Signal nicht gefunden',
|
||||
subtitle: 'Das ausgewählte Signal konnte nicht geladen werden.',
|
||||
},
|
||||
}
|
||||
|
||||
export function MarketSignalEmptyState({ variant }: { variant: EmptyVariant }) {
|
||||
const { icon: Icon, title, subtitle } = VARIANTS[variant]
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
minHeight: 300,
|
||||
gap: 1.5,
|
||||
p: 4,
|
||||
color: 'text.secondary',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: '50%',
|
||||
bgcolor: 'rgba(148,163,184,0.12)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Icon size={24} color="#94a3b8" />
|
||||
</Box>
|
||||
<Box sx={{ textAlign: 'center', maxWidth: 320 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: 600, color: 'text.primary', mb: 0.5 }}>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
||||
{subtitle}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user