PUEDES HACER QUE TENGA ESTO UN MODO OSCURO?

// src/App.tsx
import React, { useState, ChangeEvent } from "react";
import { FolderTree, Download, AlertCircle, CheckCircle } from "lucide-react";
import useTheme from "./useTheme";

// Definición de tipos para TreeNode (si aún lo usas)
interface TreeNode {
  name: string;
  type: "folder" | "file";
  children?: TreeNode[];
}

function App() {
  const [folderStructure, setFolderStructure] = useState<string>("");
  const [treeData, setTreeData] = useState<TreeNode[]>([]);
  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 { tree, structure, treeNodes } = await listFolderContents(files);
        setFolderStructure(structure);
        setTreeData(treeNodes);
        downloadTextFile(structure, "folder_structure.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<{ tree: string; structure: string; treeNodes: TreeNode[] }> => {
    let treeStructure = "Folder Structure:\n\n";
    let fileContents = "\n\nFile Contents:\n";
    const files = Array.from(fileList);
    const root: TreeNode = {
      name: "Root",
      type: "folder",
      children: [],
    };

    // Función para agregar un archivo o carpeta al árbol
    const addToTree = async (path: string[], file: File) => {
      let currentNode = root;

      for (let i = 0; i < path.length; i++) {
        const part = path[i];
        let child = currentNode.children?.find(
          (c) => c.name === part && c.type === "folder"
        );

        if (!child) {
          child = {
            name: part,
            type: "folder",
            children: [],
          };
          currentNode.children?.push(child);
        }

        currentNode = child;
      }

      // Agregar el archivo
      const fileName = file.name;
      const fileNode: TreeNode = {
        name: fileName,
        type: "file",
        // Opcional: leer el contenido del archivo
        // content: await readFileContent(file),
      };

      currentNode.children?.push(fileNode);
    };

    // Inicializar children de root
    root.children = [];

    // Agregar todos los archivos al árbol
    for (const file of files) {
      const relativePath = file.webkitRelativePath || file.name;
      const parts = relativePath.split("/").filter(Boolean);
      if (parts.length > 1) {
        const folderPath = parts.slice(0, -1);
        await addToTree(folderPath, file);
      } else {
        // Archivo en la raíz
        await addToTree([], file);
      }
    }

    // Función para generar la estructura del árbol como texto
    const generateTreeText = (node: TreeNode, prefix: string = ""): string => {
      let treeStr = "";

      if (node.name !== "Root") {
        // Añadir una barra al final si es una carpeta
        const displayName =
          node.type === "folder" ? `${node.name}/` : node.name;
        treeStr += `${prefix}${
          node.type === "folder" ? "├─ " : "├─ "
        }${displayName}\n`;
        prefix += node.type === "folder" ? "│  " : "   ";
      }

      if (node.children && node.children.length > 0) {
        node.children.forEach((child, index) => {
          const isLast = index === node.children!.length - 1;
          const connector = isLast ? "└─ " : "├─ ";
          const newPrefix = prefix + (isLast ? "    " : "│   ");
          const displayName =
            child.type === "folder" ? `${child.name}/` : child.name;
          treeStr += `${prefix}${connector}${displayName}\n`;
          if (child.type === "folder" && child.children) {
            treeStr += generateTreeText(child, newPrefix);
          }
        });
      }

      return treeStr;
    };

    // Generar la estructura del árbol
    treeStructure += generateTreeText(root);

    // Generar el contenido de los archivos
    for (const file of files) {
      const relativePath = file.webkitRelativePath || file.name;
      const fileExtension = relativePath.split(".").pop()?.toLowerCase();

      // Filtrar solo archivos de texto para evitar mostrar contenido binario
      const isTextFile = ["txt", "js", "css", "html", "json", "md"].includes(
        fileExtension || ""
      );

      fileContents += `\nFile: ${relativePath}\n`;
      fileContents += `${"=".repeat(relativePath.length + 6)}\n`;

      if (isTextFile) {
        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";
        }
      } else {
        // Indicar que el archivo es binario o no legible
        fileContents += "Contenido binario o no legible.\n\n";
      }
    }

    // Combinar la estructura del árbol y el contenido de los archivos
    const fullStructure = treeStructure + fileContents;

    return { tree: treeStructure, structure: fullStructure, treeNodes: [] };
  };

  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 Visualización
      </h1>
      <div className="bg-white 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-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}
        />

        {/* 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"
              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">Procesando...</span>
          </div>
        )}

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

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

            <div className="flex items-center mt-4 text-green-600">
              <CheckCircle className="mr-2 w-5 h-5" />
              <span>¡Estructura generada y descargada exitosamente!</span>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

export default App;


MIRA QUE TENGO ESTO:

// src/useTheme.ts
import { useState, useEffect } from "react";

const useTheme = () => {
  const [isDarkMode, setIsDarkMode] = useState<boolean>(() => {
    const savedTheme = localStorage.getItem("theme");
    if (savedTheme) {
      return savedTheme === "dark";
    } else {
      // Detectar la preferencia del usuario
      return window.matchMedia("(prefers-color-scheme: dark)").matches;
    }
  });

  useEffect(() => {
    if (isDarkMode) {
      document.documentElement.classList.add("dark");
      localStorage.setItem("theme", "dark");
    } else {
      document.documentElement.classList.remove("dark");
      localStorage.setItem("theme", "light");
    }
  }, [isDarkMode]);

  const toggleTheme = () => setIsDarkMode((prev) => !prev);

  return { isDarkMode, toggleTheme };
};

export default useTheme;