⚛MicroCore: Framework PHP+Tailwind Minimalista (Single-File Pattern)

Para cumplir con los requerimientos, debes utilizar **⚛MicroCore**.

**⚛MicroCore: Framework PHP+Tailwind Minimalista (Single-File Pattern)**
``
estructura/
├── index.php            # Lógica superior + HTML (Tailwind CDN)
├── config.php           # MAX_UPLOAD_SIZE, ALLOWED_FILE_TYPES
├── components/          # header|footer|sidebar|modal.php
└── assets/uploads/      # Archivos subidos
`` 

**Reglas clave:**
1. **Lógica**: Implementar al inicio de `index.php` (antes del HTML)
2. **UI**: 
   - Contenido principal → `#dynamic-content`
   - Feedback → `showModal(title, content)`
   - Navegación → Añadir items en `sidebar.php`
3. **Assets**: Guardar en `/assets/uploads/` con `uniqid()`

**Componentes predefinidos:**
- `header.php`: Título + menú responsive
- `sidebar.php`: Menú colapsable (toggle: `toggleSidebar()`)
- `modal.php`: Ventana emergente (`showModal()`)
- `footer.php`: Info básica

**Ejemplo de flujo (upload):**
1. Validar en `index.php` (usar `config.php`)
2. Guardar en `/assets/uploads/`
3. Mostrar resultado en `#dynamic-content` o `showModal()`

**Tokens clave:** `dynamic-content`, `showModal`, `toggleSidebar`, `components/*.php`, `config.php`

### Código Implementado en los archivos del Microframework

#### 1. config.php
``php
<?php
// Configuración básica de la aplicación
define('APP_NAME', 'MicroApp Toolset');
define('MAX_UPLOAD_SIZE', 5); // 5MB
define('ALLOWED_FILE_TYPES', ['image/jpeg', 'image/png', 'application/pdf', 'text/plain']);

// Funciones útiles
function sanitize_input($data) {
    return htmlspecialchars(strip_tags(trim($data)));
}

function format_bytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB'];
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024);
    $pow = min($pow, count($units) - 1);
    return round($bytes / (1024 ** $pow), $precision) . ' ' . $units[$pow];
}
?>
``

#### 2. index.php
``php
<?php
require_once 'config.php';

// Lógica de la aplicación (ejemplo: procesamiento de archivos)
$upload_message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userfile'])) {
    $file = $_FILES['userfile'];

    if ($file['error'] === UPLOAD_ERR_OK) {
        if (in_array($file['type'], ALLOWED_FILE_TYPES)) {
            if ($file['size'] <= MAX_UPLOAD_SIZE * 1024 * 1024) {
                $upload_path = 'assets/uploads/' . uniqid() . '_' . basename($file['name']);
                if (move_uploaded_file($file['tmp_name'], $upload_path)) {
                    $upload_message = "¡Archivo procesado con éxito!";
                    // Aquí iría la lógica específica de procesamiento
                } else {
                    $upload_message = "Error al guardar el archivo.";
                }
            } else {
                $upload_message = "Archivo demasiado grande. Límite: " . MAX_UPLOAD_SIZE . "MB";
            }
        } else {
            $upload_message = "Tipo de archivo no permitido.";
        }
    } else {
        $upload_message = "Error en la subida: " . $file['error'];
    }
}
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= APP_NAME ?></title>
    <!-- Tailwind CSS via CDN (sin necesidad de instalación) -->
    <script src="https://cdn.tailwindcss.com"></script>
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                    }
                }
            }
        }
    </script>
</head>
<body class="bg-gray-50 min-h-screen flex flex-col">
    <?php include 'components/header.php'; ?>

    <div class="flex flex-1">
        <?php include 'components/sidebar.php'; ?>

        <main class="flex-1 p-6">
            <h1 class="text-2xl font-bold text-gray-800 mb-6">Herramienta de Procesamiento</h1>

            <!-- Ejemplo de componente funcional -->
            <div class="bg-white rounded-lg shadow p-6 mb-6">
                <h2 class="text-xl font-semibold mb-4">Procesar Archivo</h2>
                <?php if ($upload_message): ?>
                    <div class="mb-4 p-4 <?= strpos($upload_message, 'éxito') !== false ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' ?> rounded">
                        <?= $upload_message ?>
                    </div>
                <?php endif; ?>

                <form method="post" enctype="multipart/form-data" class="space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">Selecciona un archivo</label>
                        <input type="file" name="userfile" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:text-sm file:font-semibold file:bg-primary file:text-white hover:file:bg-primary-dark">
                    </div>
                    <button type="submit" class="px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition">Procesar</button>
                </form>
            </div>

            <!-- Espacio para componentes dinámicos -->
            <div id="dynamic-content" class="bg-white rounded-lg shadow p-6">
                <?php /* Aquí se incluirían componentes según la ruta o parámetros */ ?>
                <p class="text-gray-500">Contenido dinámico aparecerá aquí.</p>
            </div>
        </main>
    </div>

    <?php include 'components/footer.php'; ?>

    <!-- Scripts básicos -->
    <script>
        // Funcionalidad básica para mostrar/ocultar sidebar
        function toggleSidebar() {
            const sidebar = document.getElementById('sidebar');
            sidebar.classList.toggle('-translate-x-full');
        }

        // Ejemplo de función para procesamiento en el cliente
        function processText(text) {
            return text.trim().toUpperCase();
        }
    </script>
</body>
</html>
``

#### 3. components/header.php
``php
<header class="bg-white shadow">
    <div class="max-w-7xl mx-auto px-4 py-4 sm:px-6 lg:px-8 flex justify-between items-center">
        <div class="flex items-center space-x-4">
            <button onclick="toggleSidebar()" class="md:hidden text-gray-500 hover:text-gray-700">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
                </svg>
            </button>
            <h1 class="text-xl font-bold text-gray-800"><?= APP_NAME ?></h1>
        </div>
        <nav class="hidden md:flex space-x-8">
            <a href="#" class="text-primary font-medium">Inicio</a>
            <a href="#" class="text-gray-500 hover:text-primary">Herramientas</a>
            <a href="#" class="text-gray-500 hover:text-primary">Documentación</a>
        </nav>
    </div>
</header>
``

#### 4. components/sidebar.php
``php
<aside id="sidebar" class="bg-gray-800 text-white w-64 fixed md:relative h-full transform -translate-x-full md:translate-x-0 transition-transform duration-200 ease-in-out z-10">
    <div class="p-4">
        <h2 class="text-xl font-bold mb-6">Menú</h2>
        <nav class="space-y-2">
            <a href="#" class="block px-4 py-2 bg-primary rounded">Procesar Texto</a>
            <a href="#" class="block px-4 py-2 hover:bg-gray-700 rounded">Optimizar Imágenes</a>
            <a href="#" class="block px-4 py-2 hover:bg-gray-700 rounded">Convertir PDF</a>
            <a href="#" class="block px-4 py-2 hover:bg-gray-700 rounded">Analizar Datos</a>
        </nav>

        <div class="mt-8 pt-4 border-t border-gray-700">
            <h3 class="font-medium mb-2">Configuración Rápida</h3>
            <div class="space-y-2">
                <label class="flex items-center space-x-2">
                    <input type="checkbox" class="rounded text-primary">
                    <span>Modo Oscuro</span>
                </label>
                <label class="flex items-center space-x-2">
                    <input type="checkbox" class="rounded text-primary" checked>
                    <span>Guardar Historial</span>
                </label>
            </div>
        </div>
    </div>
</aside>
``

#### 5. components/footer.php
``php
<footer class="bg-gray-800 text-white py-6 mt-auto">
    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="flex flex-col md:flex-row justify-between items-center">
            <div class="mb-4 md:mb-0">
                <p class="text-sm">&copy; <?= date('Y') ?> <?= APP_NAME ?>. Todos los derechos reservados.</p>
            </div>
            <div class="flex space-x-6">
                <a href="#" class="text-gray-300 hover:text-white">Términos</a>
                <a href="#" class="text-gray-300 hover:text-white">Privacidad</a>
                <a href="#" class="text-gray-300 hover:text-white">Documentación</a>
            </div>
        </div>
    </div>
</footer>
``

#### 6. components/modal.php
``php
<div id="modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-20">
    <div class="bg-white rounded-lg shadow-xl max-w-md w-full p-6">
        <div class="flex justify-between items-center mb-4">
            <h3 class="text-lg font-bold" id="modal-title">Título del Modal</h3>
            <button onclick="document.getElementById('modal').classList.add('hidden')" class="text-gray-500 hover:text-gray-700">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                </svg>
            </button>
        </div>
        <div id="modal-content">
            <!-- Contenido dinámico irá aquí -->
        </div>
        <div class="mt-4 flex justify-end space-x-3">
            <button onclick="document.getElementById('modal').classList.add('hidden')" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">Cancelar</button>
            <button id="modal-action" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary-dark">Aceptar</button>
        </div>
    </div>
</div>

<script>
    // Función para mostrar modales
    function showModal(title, content, actionText = 'Aceptar', actionCallback = null) {
        document.getElementById('modal-title').textContent = title;
        document.getElementById('modal-content').innerHTML = content;
        document.getElementById('modal-action').textContent = actionText;

        const modal = document.getElementById('modal');
        modal.classList.remove('hidden');

        if (actionCallback) {
            document.getElementById('modal-action').onclick = function() {
                actionCallback();
                modal.classList.add('hidden');
            };
        } else {
            document.getElementById('modal-action').onclick = function() {
                modal.classList.add('hidden');
            };
        }
    }
</script>
``