import { useStore } from '@nanostores/react'; import { memo, useMemo } from 'react'; import { workbenchStore } from '~/lib/stores/workbench'; import { classNames } from '~/utils/classNames'; import { motion } from 'framer-motion'; interface FileStatusIndicatorProps { className?: string; showDetails?: boolean; } export const FileStatusIndicator = memo(({ className = '', showDetails = true }: FileStatusIndicatorProps) => { const unsavedFiles = useStore(workbenchStore.unsavedFiles); const files = useStore(workbenchStore.files); const stats = useMemo(() => { let totalFiles = 0; let totalFolders = 0; let totalSize = 0; Object.entries(files).forEach(([_path, dirent]) => { if (dirent?.type === 'file') { totalFiles++; totalSize += dirent.content?.length || 0; } else if (dirent?.type === 'folder') { totalFolders++; } }); return { totalFiles, totalFolders, unsavedCount: unsavedFiles.size, totalSize: formatFileSize(totalSize), modifiedPercentage: totalFiles > 0 ? Math.round((unsavedFiles.size / totalFiles) * 100) : 0, }; }, [files, unsavedFiles]); function formatFileSize(bytes: number): string { if (bytes === 0) { return '0 B'; } const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`; } const getStatusColor = () => { if (stats.unsavedCount === 0) { return 'text-green-500'; } if (stats.modifiedPercentage > 50) { return 'text-red-500'; } if (stats.modifiedPercentage > 20) { return 'text-yellow-500'; } return 'text-orange-500'; }; return (
{/* Status dot with pulse animation */}
0 ? [1, 1.2, 1] : 1, }} transition={{ duration: 2, repeat: stats.unsavedCount > 0 ? Infinity : 0, repeatType: 'loop', }} className={classNames( 'w-2 h-2 rounded-full', getStatusColor(), stats.unsavedCount > 0 ? 'bg-current' : 'bg-green-500', )} /> {stats.unsavedCount === 0 ? 'All saved' : `${stats.unsavedCount} unsaved`}
{showDetails && ( <> {/* File count */}
{stats.totalFiles} files
{/* Folder count */}
{stats.totalFolders} folders
{/* Total size */}
{stats.totalSize}
{/* Progress bar for unsaved files */} {stats.unsavedCount > 0 && (
{stats.modifiedPercentage}% modified
50 ? 'bg-red-500' : stats.modifiedPercentage > 20 ? 'bg-yellow-500' : 'bg-orange-500', )} />
)} )}
); }); FileStatusIndicator.displayName = 'FileStatusIndicator';