diff --git a/app/components/header/HeaderActionButtons.client.tsx b/app/components/header/HeaderActionButtons.client.tsx index c4c24f255..989725810 100644 --- a/app/components/header/HeaderActionButtons.client.tsx +++ b/app/components/header/HeaderActionButtons.client.tsx @@ -2,7 +2,7 @@ import { useStore } from '@nanostores/react'; import { chatStore } from '~/lib/stores/chat'; import { workbenchStore } from '~/lib/stores/workbench'; import { classNames } from '~/utils/classNames'; -import { useState } from 'react'; +import { useState, useRef } from 'react'; import { toast } from 'react-toastify'; interface HeaderActionButtonsProps {} @@ -10,13 +10,102 @@ interface HeaderActionButtonsProps {} export function HeaderActionButtons({}: HeaderActionButtonsProps) { const showWorkbench = useStore(workbenchStore.showWorkbench); const { showChat } = useStore(chatStore); - const [showComingSoon, setShowComingSoon] = useState(false); + const [isSyncing, setIsSyncing] = useState(false); + const fileInputRef = useRef(null); const canHideChat = showWorkbench || !showChat; - const handleSyncFiles = () => { - setShowComingSoon(true); - setTimeout(() => setShowComingSoon(false), 2000); + const handleSyncFiles = async () => { + setIsSyncing(true); + try { + // Créer un input file pour sélectionner un fichier + const input = document.createElement('input'); + input.type = 'file'; + // Définir les types de fichiers acceptés + input.accept = '.js,.jsx,.ts,.tsx,.css,.scss,.html,.json,.md,.txt'; + // Désactiver la sélection multiple + input.multiple = false; + input.webkitdirectory = false; + input.directory = false; + + input.onchange = async (e) => { + const file = (e.target as HTMLInputElement).files?.[0]; + if (!file) { + setIsSyncing(false); + return; + } + + // Vérifier si c'est un dossier (au cas où) + if (file.size === 0 && file.type === "") { + toast.error('Folders are not supported, please select a single file'); + setIsSyncing(false); + return; + } + + // Vérifier la taille du fichier (5MB max) + if (file.size > 5 * 1024 * 1024) { + toast.error(`File "${file.name}" is too large (max 5MB)`); + setIsSyncing(false); + return; + } + + try { + console.log('Reading file:', file.name, 'Type:', file.type); + const content = await file.text(); + + // Vérifier si le contenu est lisible + if (!content) { + toast.error(`File "${file.name}" appears to be empty`); + setIsSyncing(false); + return; + } + + // Vérifier l'extension du fichier + const fileExtension = file.name.split('.').pop()?.toLowerCase(); + if (!fileExtension) { + toast.error(`File "${file.name}" has no extension`); + setIsSyncing(false); + return; + } + + const allowedExtensions = ['js', 'jsx', 'ts', 'tsx', 'css', 'scss', 'html', 'json', 'md', 'txt']; + if (!allowedExtensions.includes(fileExtension)) { + toast.error(`File type ".${fileExtension}" is not supported. Allowed types: ${allowedExtensions.join(', ')}`); + setIsSyncing(false); + return; + } + + await workbenchStore.addFile({ + name: file.name, + content, + path: file.name + }); + + toast.success(`File "${file.name}" imported successfully`); + } catch (error) { + console.error('Error details:', { + fileName: file.name, + fileType: file.type, + fileSize: file.size, + error + }); + + if (error instanceof Error) { + toast.error(`Failed to read "${file.name}": ${error.message}`); + } else { + toast.error(`Failed to read "${file.name}". Please try another file.`); + } + } finally { + setIsSyncing(false); + } + }; + + input.click(); + } catch (error) { + console.error('Import error:', error); + toast.error('Failed to start import process'); + setIsSyncing(false); + } }; const handlePushToGitHub = async () => { @@ -80,27 +169,19 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) { Download
-
- -
+