Spaces:
Paused
Paused
| import { ReactNode, useState } from 'react'; | |
| import { Database } from 'lucide-react'; | |
| import { cn } from '@/lib/utils'; | |
| import SourceLink, { DataSource } from './SourceLink'; | |
| import { DataSourceSelector, DataSourceConfig, DataSourceTrigger } from './DataSourceSelector'; | |
| import { Button } from '@/components/ui/button'; | |
| interface CyberCardProps { | |
| children: ReactNode; | |
| className?: string; | |
| variant?: 'default' | 'bordered' | 'glowing'; | |
| header?: string; | |
| source?: DataSource; | |
| /** Enable data source switching */ | |
| configurable?: boolean; | |
| /** Initial data source config */ | |
| dataSource?: DataSourceConfig; | |
| /** Called when data source changes */ | |
| onDataSourceChange?: (source: DataSourceConfig) => void; | |
| } | |
| const CyberCard = ({ | |
| children, | |
| className, | |
| variant = 'default', | |
| header, | |
| source, | |
| configurable = false, | |
| dataSource, | |
| onDataSourceChange | |
| }: CyberCardProps) => { | |
| const [selectedSource, setSelectedSource] = useState<DataSourceConfig | undefined>(dataSource); | |
| const [selectorOpen, setSelectorOpen] = useState(false); | |
| const handleSourceChange = (newSource: DataSourceConfig) => { | |
| setSelectedSource(newSource); | |
| onDataSourceChange?.(newSource); | |
| }; | |
| return ( | |
| <div | |
| className={cn( | |
| "relative bg-card/80 backdrop-blur-sm overflow-hidden", | |
| variant === 'bordered' && "cyber-border", | |
| variant === 'glowing' && "box-glow border border-primary/30", | |
| variant === 'default' && "border border-border/50", | |
| className | |
| )} | |
| > | |
| {header && ( | |
| <div className="flex items-center gap-2 px-4 py-2 border-b border-border/50 bg-secondary/50"> | |
| <div className="w-2 h-2 rounded-full bg-primary animate-pulse" /> | |
| <span className="font-display text-xs uppercase tracking-wider text-primary"> | |
| {header} | |
| </span> | |
| <div className="flex-1" /> | |
| {configurable && ( | |
| <> | |
| <DataSourceTrigger | |
| selectedSource={selectedSource} | |
| onClick={() => setSelectorOpen(true)} | |
| /> | |
| <DataSourceSelector | |
| selectedSource={selectedSource} | |
| onSourceChange={handleSourceChange} | |
| open={selectorOpen} | |
| onOpenChange={setSelectorOpen} | |
| /> | |
| </> | |
| )} | |
| {source && <SourceLink source={source} variant="badge" />} | |
| <span className="font-mono text-xs text-muted-foreground"> | |
| {new Date().toLocaleTimeString('da-DK', { hour: '2-digit', minute: '2-digit', second: '2-digit' })} | |
| </span> | |
| </div> | |
| )} | |
| <div className="p-4 sm:p-6"> | |
| {children} | |
| </div> | |
| {/* Corner accents */} | |
| <div className="absolute top-0 left-0 w-4 h-4 border-l-2 border-t-2 border-primary/50" /> | |
| <div className="absolute top-0 right-0 w-4 h-4 border-r-2 border-t-2 border-primary/50" /> | |
| <div className="absolute bottom-0 left-0 w-4 h-4 border-l-2 border-b-2 border-primary/50" /> | |
| <div className="absolute bottom-0 right-0 w-4 h-4 border-r-2 border-b-2 border-primary/50" /> | |
| </div> | |
| ); | |
| }; | |
| export default CyberCard; | |