Spaces:
Sleeping
Sleeping
| import { useState } from 'react'; | |
| import { motion, AnimatePresence } from 'framer-motion'; | |
| import { ChevronDown, Code2, BarChart3, Database, AlertOctagon } from 'lucide-react'; | |
| import styles from './TechnicalMetadata.module.css'; | |
| function Section({ icon: Icon, title, defaultOpen = false, children }) { | |
| const [open, setOpen] = useState(defaultOpen); | |
| return ( | |
| <div className={styles.section}> | |
| <button | |
| className={styles.sectionToggle} | |
| onClick={() => setOpen(!open)} | |
| aria-expanded={open} | |
| > | |
| <div className={styles.sectionLeft}> | |
| <div className={styles.sectionIcon}><Icon size={14} /></div> | |
| <span>{title}</span> | |
| </div> | |
| <ChevronDown | |
| size={15} | |
| style={{ transform: open ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.2s ease', color: 'var(--text-muted)' }} | |
| /> | |
| </button> | |
| <AnimatePresence> | |
| {open && ( | |
| <motion.div | |
| className={styles.sectionBody} | |
| initial={{ height: 0, opacity: 0 }} | |
| animate={{ height: 'auto', opacity: 1 }} | |
| exit={{ height: 0, opacity: 0 }} | |
| transition={{ duration: 0.2 }} | |
| > | |
| <div className={styles.sectionContent}>{children}</div> | |
| </motion.div> | |
| )} | |
| </AnimatePresence> | |
| </div> | |
| ); | |
| } | |
| function MetaRow({ label, value, mono = false, highlight = false }) { | |
| return ( | |
| <div className={`${styles.metaRow} ${highlight ? styles.metaRowHighlight : ''}`}> | |
| <span className={styles.metaLabel}>{label}</span> | |
| <span className={`${styles.metaValue} ${mono ? 'font-mono' : ''}`}>{value}</span> | |
| </div> | |
| ); | |
| } | |
| export default function TechnicalMetadata({ result }) { | |
| return ( | |
| <div className={styles.wrapper}> | |
| <div className={styles.header}> | |
| <Code2 size={15} /> | |
| <span>Technical Metadata</span> | |
| <span className={styles.headerNote}>Generative fingerprints & frequency signals</span> | |
| </div> | |
| <div className={styles.sections}> | |
| {/* FFT Analysis */} | |
| <Section icon={BarChart3} title="Frequency Analysis (FFT)" defaultOpen={true}> | |
| <MetaRow label="Spectral Anomaly" value={result.fft.spectralAnomaly ? '⚠ Detected' : '✓ None'} highlight={result.fft.spectralAnomaly} /> | |
| <MetaRow label="Peak Frequency" value={result.fft.peakFrequency} mono /> | |
| <MetaRow label="Anomaly Bands" value={result.fft.anomalyBands.join(', ')} mono /> | |
| <MetaRow label="DCT Coefficients" value={result.fft.dctCoefficients} /> | |
| <MetaRow label="Noise Pattern" value={result.fft.noisePattern} /> | |
| </Section> | |
| {/* Artifacts */} | |
| <Section icon={AlertOctagon} title="Generative Fingerprints" defaultOpen={true}> | |
| {result.artifacts.map((a) => ( | |
| <div key={a.id} className={styles.artifactDetail}> | |
| <div className={styles.artifactDetailHeader}> | |
| <span className={`${styles.sev} ${styles['sev_' + a.severity]}`}>{a.severity.toUpperCase()}</span> | |
| <span className={styles.artifactDetailType}>{a.type}</span> | |
| </div> | |
| <p className={styles.artifactDetailText}>{a.detail}</p> | |
| </div> | |
| ))} | |
| </Section> | |
| {/* File metadata */} | |
| <Section icon={Database} title="File Metadata"> | |
| {Object.entries(result.metadata) | |
| .filter(([key]) => key !== 'heatmapPreview') | |
| .map(([key, val]) => ( | |
| <MetaRow | |
| key={key} | |
| label={key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase())} | |
| value={val} | |
| mono | |
| /> | |
| ))} | |
| </Section> | |
| </div> | |
| </div> | |
| ); | |
| } | |