mria lo que tengo:

// src/App.tsx
import React, { useState, ChangeEvent, InputHTMLAttributes } from "react";
import {
  FolderTree,
  Download,
  CheckCircle,
  AlertCircle,
  Sun,
  Moon,
} from "lucide-react";
import useTheme from "./useTheme"; // Asegúrate de crear este archivo como se mostró anteriormente

// Extender las propiedades del input para incluir webkitdirectory
interface DirectoryInputProps extends InputHTMLAttributes<HTMLInputElement> {
  webkitdirectory?: boolean;
}

interface TreeNode {
  name: string;
  children?: TreeNode[];
}

function App() {
  const [folderStructure, setFolderStructure] = useState<string>("");
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [error, setError] = useState<string>("");
  const { isDarkMode, toggleTheme } = useTheme();

  const handleFolderSelect = async (event: ChangeEvent<HTMLInputElement>) => {
    const files = event.target.files;
    console.log(`Número de archivos seleccionados: ${files?.length}`); // Depuración
    if (files && files.length > 0) {
      // Opcional: Listar los archivos seleccionados en consola
      for (let i = 0; i < files.length; i++) {
        console.log(`Archivo ${i + 1}: ${files[i].webkitRelativePath}`);
      }

      setIsLoading(true);
      setError("");
      try {
        const structure = await listFolderContents(files);
        setFolderStructure(structure);
        downloadTextFile(structure, "folder_structure_and_contents.txt");
      } catch (err) {
        console.error(err); // Depuración adicional
        setError("Ocurrió un error al procesar los archivos.");
      } finally {
        setIsLoading(false);
      }
    }
  };

  const listFolderContents = async (fileList: FileList): Promise<string> => {
    const root: TreeNode = { name: "", children: [] };

    const files = Array.from(fileList);

    // Construir el árbol
    for (const file of files) {
      const relativePath = file.webkitRelativePath || file.name;
      const parts = relativePath.split("/");
      let currentNode = root;

      parts.forEach((part) => {
        if (!currentNode.children) {
          currentNode.children = [];
        }

        let childNode = currentNode.children.find(
          (child) => child.name === part
        );
        if (!childNode) {
          childNode = { name: part, children: [] };
          currentNode.children.push(childNode);
        }

        currentNode = childNode;
      });
    }

    console.log("Estructura del Árbol:", root); // Depuración

    // Generar la representación en cadena del árbol
    let treeStructure = "Folder Structure:\n\n";

    const generateTreeString = (
      node: TreeNode,
      prefix: string = "",
      isLast: boolean = true
    ): void => {
      if (node.name !== "") {
        // Ignorar la raíz
        treeStructure += `${prefix}${isLast ? "└─ " : "├─ "}${node.name}\n`;
      }

      const children = node.children || [];
      children.forEach((child, index) => {
        const last = index === children.length - 1;
        const newPrefix = prefix + (isLast ? "    " : "│   ");
        generateTreeString(child, newPrefix, last);
      });
    };

    generateTreeString(root);

    // Generar el contenido de los archivos
    let fileContents = "\nFile Contents:\n";
    for (const file of files) {
      const relativePath = file.webkitRelativePath || file.name;
      fileContents += `\nFile: ${relativePath}\n`;
      fileContents += "=".repeat(relativePath.length + 6) + "\n";
      try {
        const content = await readFileContent(file);
        fileContents += `${content}\n\n`;
      } catch (readError) {
        console.error(`Error leyendo el archivo ${relativePath}:`, readError);
        fileContents += "Error al leer el contenido del archivo.\n\n";
      }
    }

    return treeStructure + fileContents;
  };

  const readFileContent = (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (event) => {
        if (event.target) {
          const content = event.target.result as string;
          resolve(content);
        }
      };
      reader.onerror = (error) => reject(error);
      reader.readAsText(file);
    });
  };

  const downloadTextFile = (content: string, fileName: string) => {
    const element = document.createElement("a");
    const file = new Blob([content], { type: "text/plain" });
    element.href = URL.createObjectURL(file);
    element.download = fileName;
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
  };

  return (
    <div className="min-h-screen bg-gray-100 dark:bg-gray-900 flex flex-col items-center justify-center p-4 transition-colors duration-500">
      {/* Encabezado con Toggle de Tema */}
      <header className="w-full max-w-2xl flex justify-between items-center mb-8">
        <div>
          <h1 className="text-4xl font-extrabold text-gray-800 dark:text-gray-200 mb-2">
            Explorador de Carpetas
          </h1>
          <p className="text-center text-gray-600 dark:text-gray-400">
            Selecciona una carpeta para visualizar su estructura y contenidos.
          </p>
        </div>
        {/* Botón de Modo Oscuro */}
        <button
          onClick={toggleTheme}
          className="p-2 rounded-full bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500"
          aria-label="Toggle Dark Mode"
        >
          {isDarkMode ? (
            <Sun className="w-5 h-5" />
          ) : (
            <Moon className="w-5 h-5" />
          )}
        </button>
      </header>

      {/* Contenedor Principal */}
      <div className="bg-white dark:bg-gray-800 p-8 rounded-lg shadow-md w-full max-w-2xl">
        {/* Botón de Selección de Carpeta */}
        <label
          htmlFor="folder-input"
          className="flex items-center justify-center w-full px-4 py-3 bg-blue-600 dark:bg-blue-500 text-white rounded-lg cursor-pointer hover:bg-blue-700 dark:hover:bg-blue-600 transition-colors duration-200"
        >
          <FolderTree className="mr-2 w-5 h-5" />
          <span className="font-medium">Seleccionar Carpeta</span>
        </label>
        <input
          id="folder-input"
          type="file"
          webkitdirectory
          className="hidden"
          onChange={handleFolderSelect}
          multiple // Añadido explícitamente
        />

        {/* Indicador de Carga */}
        {isLoading && (
          <div className="flex items-center mt-6">
            <svg
              className="animate-spin -ml-1 mr-3 h-5 w-5 text-blue-500 dark:text-blue-400"
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
            >
              <circle
                className="opacity-25"
                cx="12"
                cy="12"
                r="10"
                stroke="currentColor"
                strokeWidth="4"
              ></circle>
              <path
                className="opacity-75"
                fill="currentColor"
                d="M4 12a8 8 0 018-8v8H4z"
              ></path>
            </svg>
            <span className="text-gray-700 dark:text-gray-300">
              Procesando...
            </span>
          </div>
        )}

        {/* Mensaje de Error */}
        {error && (
          <div className="flex items-center mt-6 text-red-600 dark:text-red-400">
            <AlertCircle className="mr-2 w-5 h-5" />
            <span>{error}</span>
          </div>
        )}

        {/* Resultados */}
        {folderStructure && !isLoading && !error && (
          <div className="mt-6">
            <div className="flex items-center justify-between mb-4">
              <h2 className="text-2xl font-semibold text-gray-800 dark:text-gray-200">
                Estructura y Contenido de la Carpeta
              </h2>
              <button
                onClick={() =>
                  downloadTextFile(
                    folderStructure,
                    "folder_structure_and_contents.txt"
                  )
                }
                className="flex items-center px-4 py-2 bg-green-500 dark:bg-green-600 text-white rounded-lg hover:bg-green-600 dark:hover:bg-green-700 transition-colors duration-200"
              >
                <Download className="mr-2 w-5 h-5" />
                Descargar
              </button>
            </div>
            <div className="bg-gray-50 dark:bg-gray-700 p-4 rounded-md shadow-inner overflow-x-auto">
              <pre className="whitespace-pre-wrap font-mono text-sm text-gray-800 dark:text-gray-100">
                {folderStructure}
              </pre>
            </div>
            <div className="flex items-center mt-4 text-green-600 dark:text-green-400">
              <CheckCircle className="mr-2 w-5 h-5" />
              <span>¡Estructura generada y descargada exitosamente!</span>
            </div>
          </div>
        )}
      </div>

      {/* Pie de Página */}
      <footer className="mt-8 text-sm text-gray-500 dark:text-gray-400">
        &copy; {new Date().getFullYear()} Tu Empresa. Todos los derechos
        reservados.
      </footer>
    </div>
  );
}

export default App;


pero necesito que apunte a las carpetas asi como aqui:

import React, { useState } from 'react';
import { FolderTree } from 'lucide-react';

function App() {
  const [folderStructure, setFolderStructure] = useState<string>('');

  const handleFolderSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const files = event.target.files;
    if (files && files.length > 0) {
      const structure = await listFolderContents(files);
      setFolderStructure(structure);
      downloadTextFile(structure, 'folder_structure_and_contents.txt');
    }
  };

  const listFolderContents = async (fileList: FileList): Promise<string> => {
    let treeStructure = 'Folder Structure:\n\n';
    let fileContents = '\nFile Contents:\n';
    const files = Array.from(fileList);
    const folderMap = new Map<string, string[]>();

    // Build folder structure
    for (const file of files) {
      const relativePath = file.webkitRelativePath || file.name;
      const parts = relativePath.split('/');
      const folderPath = parts.slice(0, -1).join('/');
      const fileName = parts[parts.length - 1];

      if (!folderMap.has(folderPath)) {
        folderMap.set(folderPath, []);
      }
      folderMap.get(folderPath)!.push(fileName);
    }

    // Generate tree structure
    const generateTree = (path: string, depth: number) => {
      const prefix = '│  '.repeat(depth);
      const files = folderMap.get(path) || [];
      
      for (let i = 0; i < files.length; i++) {
        const isLast = i === files.length - 1;
        const fileName = files[i];
        const fullPath = path ? `${path}/${fileName}` : fileName;
        
        treeStructure += `${prefix}${isLast ? '└─ ' : '├─ '}${fileName}\n`;
        
        if (folderMap.has(fullPath)) {
          generateTree(fullPath, depth + 1);
        }
      }
    };

    generateTree('', 0);

    // Generate file contents
    for (const file of files) {
      const relativePath = file.webkitRelativePath || file.name;
      fileContents += `\nFile: ${relativePath}\n`;
      fileContents += '='.repeat(relativePath.length + 6) + '\n';
      const content = await readFileContent(file);
      fileContents += `${content}\n\n`;
    }

    return treeStructure + fileContents;
  };

  const readFileContent = (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (event) => {
        if (event.target) {
          const content = event.target.result as string;
          resolve(content);
        }
      };
      reader.onerror = (error) => reject(error);
      reader.readAsText(file);
    });
  };

  const downloadTextFile = (content: string, fileName: string) => {
    const element = document.createElement('a');
    const file = new Blob([content], { type: 'text/plain' });
    element.href = URL.createObjectURL(file);
    element.download = fileName;
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
  };

  return (
    <div className="min-h-screen bg-gray-100 flex flex-col items-center justify-center p-4">
      <h1 className="text-3xl font-bold mb-6">Estructura de Carpetas y Contenido de Archivos</h1>
      <div className="bg-white p-8 rounded-lg shadow-md w-full max-w-2xl">
        <label htmlFor="folder-input" className="flex items-center justify-center w-full px-4 py-2 bg-blue-500 text-white rounded-lg cursor-pointer hover:bg-blue-600 transition-colors">
          <FolderTree className="mr-2" />
          Seleccionar Carpeta
        </label>
        <input
          id="folder-input"
          type="file"
          webkitdirectory="true"
          directory=""
          className="hidden"
          onChange={handleFolderSelect}
        />
        {folderStructure && (
          <div className="mt-4">
            <h2 className="text-xl font-semibold mb-2">Estructura y contenido de la carpeta:</h2>
            <pre className="bg-gray-100 p-4 rounded-md overflow-x-auto text-sm whitespace-pre-wrap">
              {folderStructure}
            </pre>
          </div>
        )}
      </div>
    </div>
  );
}

export default App;