| import React from 'react' |
| import { Grid, Card, Text, Title, Group, Box, Button, Stack, Progress } from '@mantine/core' |
| import { IconSearch, IconCube, IconGridPattern } from '@tabler/icons-react' |
| import { useXRD } from '../context/XRDContext' |
|
|
| const ResultsHero = () => { |
| const { modelResults, setIsLogitDrawerOpen } = useXRD() |
| |
| |
| const cardAnimation = { |
| animation: 'slideIn 0.5s ease-out forwards', |
| opacity: 0, |
| } |
| |
| const keyframes = ` |
| @keyframes slideIn { |
| from { |
| opacity: 0; |
| transform: translateY(20px); |
| } |
| to { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| } |
| ` |
| |
| if (!modelResults || !modelResults.predictions?.phase_predictions) { |
| return null |
| } |
| |
| const predictions = modelResults.predictions.phase_predictions |
| |
| |
| const crystalSystem = predictions.find(p => p.phase === 'Crystal System') |
| const spaceGroup = predictions.find(p => p.phase === 'Space Group') |
| const latticeParams = predictions.find(p => p.is_lattice) |
| |
| const getConfidenceColor = (confidence) => { |
| if (confidence >= 0.8) return 'green' |
| if (confidence >= 0.5) return 'yellow' |
| return 'orange' |
| } |
| |
| return ( |
| <> |
| <style>{keyframes}</style> |
| <Grid gutter="md" mb="lg"> |
| {/* Card 1: Crystal System */} |
| <Grid.Col span={{ base: 12, sm: 6, md: 3 }}> |
| <Card |
| shadow="sm" |
| padding="lg" |
| radius="md" |
| withBorder |
| h="100%" |
| style={{ |
| ...cardAnimation, |
| animationDelay: '0.1s', |
| borderLeft: '4px solid #9775fa', |
| background: 'linear-gradient(135deg, #ffffff 0%, #f8f4ff 100%)' |
| }} |
| > |
| <Stack gap="xs" align="center"> |
| <IconCube size={32} color="#9775fa" /> |
| <Text size="xs" c="dimmed" tt="uppercase" fw={600}> |
| Crystal System |
| </Text> |
| <Title order={3} ta="center" style={{ fontWeight: 700 }}> |
| {crystalSystem?.predicted_class || 'N/A'} |
| </Title> |
| </Stack> |
| </Card> |
| </Grid.Col> |
| |
| {/* Card 2: Space Group */} |
| <Grid.Col span={{ base: 12, sm: 6, md: 3 }}> |
| <Card |
| shadow="sm" |
| padding="lg" |
| radius="md" |
| withBorder |
| h="100%" |
| style={{ |
| ...cardAnimation, |
| animationDelay: '0.2s', |
| borderLeft: '4px solid #1e88e5', |
| background: 'linear-gradient(135deg, #ffffff 0%, #f0f7ff 100%)' |
| }} |
| > |
| <Stack gap="xs" align="center"> |
| <IconGridPattern size={32} color="#1e88e5" /> |
| <Text size="xs" c="dimmed" tt="uppercase" fw={600}> |
| Space Group |
| </Text> |
| <Title order={3} ta="center" style={{ fontWeight: 700 }}> |
| {spaceGroup?.predicted_class || 'N/A'} |
| </Title> |
| {spaceGroup?.space_group_symbol && ( |
| <Text size="sm" c="dimmed" style={{ fontFamily: 'monospace' }}> |
| {spaceGroup.space_group_symbol} |
| </Text> |
| )} |
| </Stack> |
| </Card> |
| </Grid.Col> |
| |
| {/* Card 3: Lattice Parameters */} |
| <Grid.Col span={{ base: 12, sm: 6, md: 3 }}> |
| <Card |
| shadow="sm" |
| padding="lg" |
| radius="md" |
| withBorder |
| h="100%" |
| style={{ |
| ...cardAnimation, |
| animationDelay: '0.3s', |
| borderLeft: '4px solid #00acc1', |
| background: 'linear-gradient(135deg, #ffffff 0%, #f0fdff 100%)' |
| }} |
| > |
| <Stack gap="xs"> |
| <Text size="xs" c="dimmed" tt="uppercase" fw={600} ta="center"> |
| Lattice Parameters |
| </Text> |
| {latticeParams?.lattice_params ? ( |
| <Box style={{ fontFamily: 'monospace', fontSize: '1.1rem' }}> |
| <Group gap="lg" justify="center"> |
| <Stack gap={4}> |
| <Text size="md">a = {latticeParams.lattice_params.a?.toFixed(3)} Å</Text> |
| <Text size="md">b = {latticeParams.lattice_params.b?.toFixed(3)} Å</Text> |
| <Text size="md">c = {latticeParams.lattice_params.c?.toFixed(3)} Å</Text> |
| </Stack> |
| <Stack gap={4}> |
| <Text size="md">α = {latticeParams.lattice_params['α']?.toFixed(2)}°</Text> |
| <Text size="md">β = {latticeParams.lattice_params['β']?.toFixed(2)}°</Text> |
| <Text size="md">γ = {latticeParams.lattice_params['γ']?.toFixed(2)}°</Text> |
| </Stack> |
| </Group> |
| </Box> |
| ) : ( |
| <Text size="sm" c="dimmed" ta="center">N/A</Text> |
| )} |
| </Stack> |
| </Card> |
| </Grid.Col> |
| |
| {/* Card 4: Confidence & Inspection */} |
| <Grid.Col span={{ base: 12, sm: 6, md: 3 }}> |
| <Card |
| shadow="sm" |
| padding="lg" |
| radius="md" |
| withBorder |
| h="100%" |
| style={{ |
| ...cardAnimation, |
| animationDelay: '0.4s', |
| borderLeft: '4px solid #fb8c00', |
| background: 'linear-gradient(135deg, #ffffff 0%, #fff8f0 100%)' |
| }} |
| > |
| <Stack gap="sm" align="center" justify="center" h="100%"> |
| <Text size="xs" c="dimmed" tt="uppercase" fw={600} ta="center"> |
| Confidence |
| </Text> |
| |
| {/* CS and SG Confidences - Compact */} |
| <Stack gap="xs" w="100%"> |
| {/* Crystal System Confidence */} |
| {crystalSystem?.confidence && ( |
| <Box> |
| <Group justify="space-between" mb={4}> |
| <Text size="xs" fw={600}>CS</Text> |
| <Text size="sm" fw={700} c={getConfidenceColor(crystalSystem.confidence)}> |
| {(crystalSystem.confidence * 100).toFixed(0)}% |
| </Text> |
| </Group> |
| <Progress |
| value={crystalSystem.confidence * 100} |
| color={getConfidenceColor(crystalSystem.confidence)} |
| size="md" |
| radius="xl" |
| /> |
| </Box> |
| )} |
| |
| {/* Space Group Confidence */} |
| {spaceGroup?.confidence && ( |
| <Box> |
| <Group justify="space-between" mb={4}> |
| <Text size="xs" fw={600}>SG</Text> |
| <Text size="sm" fw={700} c={getConfidenceColor(spaceGroup.confidence)}> |
| {(spaceGroup.confidence * 100).toFixed(0)}% |
| </Text> |
| </Group> |
| <Progress |
| value={spaceGroup.confidence * 100} |
| color={getConfidenceColor(spaceGroup.confidence)} |
| size="md" |
| radius="xl" |
| /> |
| </Box> |
| )} |
| </Stack> |
| |
| <Button |
| variant="subtle" |
| leftSection={<IconSearch size={16} />} |
| size="sm" |
| onClick={() => setIsLogitDrawerOpen(true)} |
| mt="xs" |
| style={{ |
| border: '1px solid #1e88e5' |
| }} |
| > |
| Inspect Logits |
| </Button> |
| </Stack> |
| </Card> |
| </Grid.Col> |
| </Grid> |
| </> |
| ) |
| } |
|
|
| export default ResultsHero |
|
|