Estos son los archivos con el code de mi sitio web con react. Te lo pasaré por partes, solo confirma que las recibiste.
Part 1:
## File: api/autenticar.php
```php
<?php
session_start();
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://localhost:3000'); // Ajusta según corresponda
header('Access-Control-Allow-Credentials: true');

require 'conexion.php';

$data = json_decode(file_get_contents('php://input'), true);

$nombre_usuario = trim($data['nombre_usuario']);
$contrasena = $data['contrasena'];

// Consulta preparada para obtener el usuario
$stmt = $conn->prepare("SELECT id, nombre_usuario, contrasena, email FROM usuarios WHERE nombre_usuario = ? OR email = ?");
$stmt->bind_param("ss", $nombre_usuario, $nombre_usuario);
$stmt->execute();
$result = $stmt->get_result();

if ($result->num_rows > 0) {
    $usuario = $result->fetch_assoc();
    if (password_verify($contrasena, $usuario['contrasena'])) {
        // Contraseña correcta
        // Establecer las variables de sesión
        $_SESSION['usuario_id'] = $usuario['id'];
        $_SESSION['nombre_usuario'] = $usuario['nombre_usuario'];
        $_SESSION['email'] = $usuario['email'];

        echo json_encode([
            'success' => true,
            'usuario' => [
                'id' => $usuario['id'],
                'nombre_usuario' => $usuario['nombre_usuario'],
                'email' => $usuario['email'],
            ]
        ]);
    } else {
        echo json_encode(['success' => false, 'message' => 'Contraseña incorrecta.']);
    }
} else {
    echo json_encode(['success' => false, 'message' => 'Usuario no encontrado.']);
}

$stmt->close();
$conn->close();
?>
```

## File: api/conexion.php
```php
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://localhost:3000'); // Ajusta según el dominio de tu frontend
header('Access-Control-Allow-Credentials: true');

// Datos de conexión a la base de datos
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "tus_noticias";

// Crear conexión
$conn = new mysqli($servername, $username, $password, $dbname);

// Establecer el conjunto de caracteres a UTF-8
$conn->set_charset("utf8");

// Verificar la conexión
if ($conn->connect_error) {
    die("Conexión fallida: " . $conn->connect_error);
}
?>
```

## File: api/obtener_articulos.php
```php
<?php
// obtener_articulos.php
session_start();

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://localhost:3000'); // Ajusta según tu dominio
header('Access-Control-Allow-Credentials: true');

// Opcional: ocultar errores y advertencias en la salida JSON
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);

require 'conexion.php';

if (isset($_GET['id'])) {
    // Caso 1: Se solicita un artículo específico
    $id = intval($_GET['id']);

    $stmt = $conn->prepare("SELECT * FROM articulos WHERE id = ?");
    $stmt->bind_param("i", $id);
    $stmt->execute();
    $result = $stmt->get_result();

    if ($result->num_rows > 0) {
        $articulo = $result->fetch_assoc();

        echo json_encode([
            'success' => true,
            'articulo' => [
                'id' => $articulo['id'],
                'titulo' => $articulo['titulo'],
                'contenido' => $articulo['contenido'],
                'fecha_publicacion' => $articulo['fecha_publicacion'],
                'autor' => $articulo['autor'],
                'imagen' => $articulo['imagen'],
            ]
        ]);
    } else {
        echo json_encode(['success' => false, 'message' => 'Artículo no encontrado.']);
    }

    $stmt->close();
} else {
    // Caso 2: Se solicitan todos los artículos
    $stmt = $conn->prepare("SELECT * FROM articulos ORDER BY fecha_publicacion DESC");
    $stmt->execute();
    $result = $stmt->get_result();

    $articulos = array();

    while ($row = $result->fetch_assoc()) {
        $articulos[] = [
            'id' => $row['id'],
            'titulo' => $row['titulo'],
            'contenido' => $row['contenido'],
            'fecha_publicacion' => $row['fecha_publicacion'],
            'autor' => $row['autor'],
            'imagen' => $row['imagen'],
        ];
    }

    echo json_encode([
        'success' => true,
        'articulos' => $articulos
    ]);

    $stmt->close();
}

$conn->close();
?>
```

## File: api/obtener_comentarios.php
```php
<?php
// obtener_comentarios.php
session_start();
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://localhost:3000'); // Ajusta según el dominio de tu frontend
header('Access-Control-Allow-Credentials: true');

require 'conexion.php';

// Obtener el ID del artículo
$articulo_id = intval($_GET['articulo_id']);

// Obtener los comentarios del artículo
$stmt = $conn->prepare("SELECT c.id, c.contenido, c.usuario_id, c.parent_comment_id, u.nombre_usuario, c.fecha_publicacion FROM comentarios c JOIN usuarios u ON c.usuario_id = u.id WHERE c.articulo_id = ? ORDER BY c.fecha_publicacion ASC");
$stmt->bind_param("i", $articulo_id);
$stmt->execute();
$result = $stmt->get_result();

$comentarios = array();

while ($row = $result->fetch_assoc()) {
    $comentarios[] = [
        'id' => $row['id'],
        'contenido' => $row['contenido'],
        'usuario_id' => $row['usuario_id'],
        'parent_comment_id' => $row['parent_comment_id'],
        'usuario' => $row['nombre_usuario'],
        'fecha' => $row['fecha_publicacion'],
    ];
}

echo json_encode(['success' => true, 'comentarios' => $comentarios]);

$stmt->close();
$conn->close();
?>
```

## File: api/obtener_total_likes.php
```php
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://localhost:3000'); // Ajusta según el dominio de tu frontend
header('Access-Control-Allow-Credentials: true');

require 'conexion.php';

$articulo_id = intval($_GET['articulo_id']);

// Obtener la cantidad total de "Me Gusta" para el artículo
$stmt = $conn->prepare("SELECT COUNT(*) as totalLikes FROM likes WHERE articulo_id = ?");
$stmt->bind_param("i", $articulo_id);
$stmt->execute();
$result = $stmt->get_result();
$totalLikes = $result->fetch_assoc()['totalLikes'];

echo json_encode(['success' => true, 'totalLikes' => $totalLikes]);

$stmt->close();
$conn->close();
?>
```

## File: api/procesar_comentarios.php
```php
<?php
session_start();
header('Access-Control-Allow-Origin: http://localhost:3000'); // Ajusta según corresponda
header('Access-Control-Allow-Credentials: true');
header('Content-Type: application/json');

// Manejar solicitud OPTIONS (preflight)
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    header('Access-Control-Allow-Methods: POST, OPTIONS'); 
    header('Access-Control-Allow-Headers: Content-Type, Authorization');
    exit(0);
}

require 'conexion.php';

// Verificar si el usuario ha iniciado sesión
if (!isset($_SESSION['usuario_id'])) {
    echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
    exit();
}


// Obtener datos del formulario
$articulo_id = isset($_POST['articulo_id']) ? intval($_POST['articulo_id']) : 0;
$usuario_id = $_SESSION['usuario_id'];
$comentario = isset($_POST['comentario']) ? trim($_POST['comentario']) : '';
$parent_comment_id = isset($_POST['parent_comment_id']) ? intval($_POST['parent_comment_id']) : null;

if ($articulo_id <= 0 || $comentario === '') {
    echo json_encode(['success' => false, 'message' => 'Datos inválidos.']);
    exit();
}

// Validar el parent_comment_id
if ($parent_comment_id !== null) {
    // Verificar si el comentario padre existe y pertenece al mismo artículo
    $stmt = $conn->prepare("SELECT id FROM comentarios WHERE id = ? AND articulo_id = ?");
    $stmt->bind_param("ii", $parent_comment_id, $articulo_id);
    $stmt->execute();
    $result = $stmt->get_result();

    if ($result->num_rows == 0) {
        echo json_encode(['success' => false, 'message' => 'El comentario al que intentas responder no existe.']);
        exit();
    }
    $stmt->close();
}

// Sanitizar el comentario para evitar ataques XSS
$comentario = htmlspecialchars($comentario, ENT_QUOTES, 'UTF-8');

// Insertar el comentario en la base de datos
$stmt = $conn->prepare("INSERT INTO comentarios (articulo_id, usuario_id, contenido, parent_comment_id) VALUES (?, ?, ?, ?)");
$stmt->bind_param("iisi", $articulo_id, $usuario_id, $comentario, $parent_comment_id);

if ($stmt->execute()) {
    echo json_encode(['success' => true]);
} else {
    echo json_encode(['success' => false, 'message' => 'Error al guardar el comentario: ' . $stmt->error]);
}

$stmt->close();
$conn->close();
?>
```

## File: api/procesar_like.php
```php
<?php
session_start();
header('Access-Control-Allow-Origin: http://localhost:3000'); // Cambia esto si tu frontend está en otro dominio
header('Access-Control-Allow-Credentials: true');
header('Content-Type: application/json');

// Manejar solicitud OPTIONS (preflight)
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    header('Access-Control-Allow-Methods: POST, OPTIONS'); 
    header('Access-Control-Allow-Headers: Content-Type, Authorization');
    exit(0);
}

require 'conexion.php';

// Verificar si el usuario ha iniciado sesión
if (!isset($_SESSION['usuario_id'])) {
    echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
    exit();
}

$articulo_id = intval($_POST['articulo_id']);
$usuario_id = $_SESSION['usuario_id'];

// Verificar si el usuario ya dio "Me Gusta" al artículo
$stmt = $conn->prepare("SELECT id FROM likes WHERE articulo_id = ? AND usuario_id = ?");
$stmt->bind_param("ii", $articulo_id, $usuario_id);
$stmt->execute();
$result = $stmt->get_result();

if ($result->num_rows > 0) {
    // Si ya dio "Me Gusta", eliminar el registro (quitar el "Me Gusta")
    $stmt = $conn->prepare("DELETE FROM likes WHERE articulo_id = ? AND usuario_id = ?");
    $stmt->bind_param("ii", $articulo_id, $usuario_id);
    $stmt->execute();
    $liked = false;
} else {
    // Si no ha dado "Me Gusta", insertarlo
    $stmt = $conn->prepare("INSERT INTO likes (articulo_id, usuario_id) VALUES (?, ?)");
    $stmt->bind_param("ii", $articulo_id, $usuario_id);
    $stmt->execute();
    $liked = true;
}

$stmt->close();
$conn->close();

echo json_encode(['success' => true, 'liked' => $liked]);
?>
```

## File: api/procesar_registro.php
```php
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');

require 'conexion.php';

$data = json_decode(file_get_contents('php://input'), true);

$nombre_usuario = trim($data['nombre_usuario']);
$email = trim($data['email']);
$contrasena = $data['contrasena'];
$confirmar_contrasena = $data['confirmar_contrasena'];

if ($contrasena !== $confirmar_contrasena) {
    echo json_encode(['success' => false, 'message' => 'Las contraseñas no coinciden.']);
    exit();
}

$stmt = $conn->prepare("SELECT id FROM usuarios WHERE nombre_usuario = ? OR email = ?");
$stmt->bind_param("ss", $nombre_usuario, $email);
$stmt->execute();
$stmt->store_result();

if ($stmt->num_rows > 0) {
    echo json_encode(['success' => false, 'message' => 'El nombre de usuario o correo electrónico ya están registrados.']);
    $stmt->close();
    exit();
}
$stmt->close();

$contrasena_hasheada = password_hash($contrasena, PASSWORD_DEFAULT);

$stmt = $conn->prepare("INSERT INTO usuarios (nombre_usuario, email, contrasena) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $nombre_usuario, $email, $contrasena_hasheada);

if ($stmt->execute()) {
    echo json_encode(['success' => true]);
} else {
    echo json_encode(['success' => false, 'message' => 'Error al registrar el usuario.']);
}

$stmt->close();
$conn->close();
?>
```

## File: api/verificar_like.php
```php
<?php
session_start();
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); // Habilitar CORS (ajustar en producción)

require 'conexion.php';

// Verificar si el usuario ha iniciado sesión
if (!isset($_SESSION['usuario_id'])) {
    echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
    exit();
}

// Incluir la conexión a la base de datos
require 'conexion.php';

$articulo_id = intval($_GET['articulo_id']);
$usuario_id = $_SESSION['usuario_id'];

// Verificar si el usuario ya dio "Me Gusta" al artículo
$stmt = $conn->prepare("SELECT id FROM likes WHERE articulo_id = ? AND usuario_id = ?");
$stmt->bind_param("ii", $articulo_id, $usuario_id);
$stmt->execute();
$result = $stmt->get_result();

$liked = ($result->num_rows > 0);

$stmt->close();
$conn->close();

echo json_encode(['success' => true, 'liked' => $liked]);
?>
```

## File: frontend/react-app/public/index.html
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <!-- public/index.html -->
    <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

```

## File: frontend/react-app/src/components/Comentarios.js
```javascript
// src/components/Comentarios.js
import React, { useEffect, useState, useContext } from 'react';
import axios from 'axios';
import { AuthContext } from '../context/AuthContext';
import { Textarea, Button } from 'flowbite-react';

function Comentarios({ articuloId }) {
  const [comentarios, setComentarios] = useState([]);
  const [nuevoComentario, setNuevoComentario] = useState('');
  const { authData } = useContext(AuthContext);
  const API_BASE_URL = 'http://localhost/mi_sitio/api'; // Ajusta según corresponda


  useEffect(() => {
    axios
  .get(`${API_BASE_URL}/obtener_comentarios.php?articulo_id=${articuloId}`)
  .then(response => {
    if (response.data.success) {
      setComentarios(response.data.comentarios);
    } else {
      console.error('Error al obtener comentarios:', response.data.message);
    }
  })
  .catch(error => {
    console.error('Error al obtener comentarios:', error);
  });

  }, [articuloId]);

  const handleSubmit = e => {
    e.preventDefault();
    if (!authData) {
      alert('Debes iniciar sesión para comentar.');
      return;
    }
    axios
    .post(
      `${API_BASE_URL}/procesar_comentarios.php`, // Asegúrate de usar el nombre correcto del script PHP
      {
        articulo_id: articuloId,
        comentario: nuevoComentario,
      },
      { withCredentials: true } 
      )
      .then(response => {
        if (response.data.success) {
          setComentarios([...comentarios, response.data.comentario]);
          setNuevoComentario('');
        } else {
          alert(response.data.message);
        }
      })
      .catch(error => {
        console.error('Error al enviar el comentario:', error);
      });
  };

  return (
    <div className="mt-10">
      <h2 className="text-2xl font-bold mb-6 text-gray-800 dark:text-gray-100">
        Comentarios
      </h2>

      {comentarios.length > 0 ? (
        <div className="space-y-6">
          {comentarios.map(comentario => (
            <div key={comentario.id} className="p-4 bg-gray-100 dark:bg-gray-800 rounded-lg">
              <p className="text-sm text-gray-600 dark:text-gray-400">
                <span className="font-semibold">{comentario.nombre_usuario}</span> - {comentario.fecha}
              </p>
              <p className="mt-2 text-gray-800 dark:text-gray-200">
                {comentario.contenido}
              </p>
            </div>
          ))}
        </div>
      ) : (
        <p className="text-gray-600 dark:text-gray-400">No hay comentarios aún. ¡Sé el primero en comentar!</p>
      )}

      {authData ? (
        <form onSubmit={handleSubmit} className="mt-8">
          <Textarea
            value={nuevoComentario}
            onChange={e => setNuevoComentario(e.target.value)}
            placeholder="Escribe tu comentario..."
            required
            rows={4}
            className="mb-4"
          />
          <Button type="submit">Enviar</Button>
        </form>
      ) : (
        <p className="mt-6 text-gray-600 dark:text-gray-400">
          <a href="/login" className="text-blue-500 hover:underline">
            Inicia sesión
          </a>{' '}
          para comentar.
        </p>
      )}
    </div>
  );
}

export default Comentarios;
```

## File: frontend/react-app/src/components/DarkModeToggle.js
```javascript
// src/components/DarkModeToggle.js
import React, { useEffect, useState } from 'react';
import { MdDarkMode, MdLightMode } from 'react-icons/md';

export function DarkModeToggle() {
  const [darkMode, setDarkMode] = useState(
    () => localStorage.getItem('theme') === 'dark'
  );

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

  return (
    <button
      onClick={() => setDarkMode(!darkMode)}
      className="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 p-2 rounded-lg"
      aria-label="Toggle Dark Mode"
    >
      {darkMode ? (
        <MdLightMode size={24} />
      ) : (
        <MdDarkMode size={24} />
      )}
    </button>
  );
}
```

## File: frontend/react-app/src/components/LikeButton.js
```javascript
// src/components/LikeButton.js
import React, { useState, useEffect, useContext } from 'react';
import axios from 'axios';
import { AuthContext } from '../context/AuthContext';
import { FiHeart } from 'react-icons/fi';
import { Button } from 'flowbite-react';


function LikeButton({ articuloId }) {
  const { authData } = useContext(AuthContext);
  const [liked, setLiked] = useState(false);
  const [totalLikes, setTotalLikes] = useState(0);
  const API_BASE_URL = 'http://localhost/mi_sitio/api'; // Ajusta según corresponda

  useEffect(() => {
    // Verificar si el usuario ha dado "Me Gusta"
    axios
      .get(`${API_BASE_URL}/verificar_like.php?articulo_id=${articuloId}`, { withCredentials: true })
      .then(response => {
        if (response.data.success) {
          setLiked(response.data.liked);
        }
      })
      .catch(error => {
        console.error('Error al verificar el like:', error);
      });

    // Obtener el total de likes
    axios
      .get(`${API_BASE_URL}/obtener_total_likes.php?articulo_id=${articuloId}`)
      .then(response => {
        setTotalLikes(response.data.totalLikes);
      })
      .catch(error => {
        console.error('Error al obtener el total de likes:', error);
      });
  }, [articuloId]);

  const handleLike = () => {
    if (!authData) {
      alert('Debes iniciar sesión para dar "Me Gusta".');
      return;
    }
    axios
    .post(
      `${API_BASE_URL}/procesar_like.php`,
      { articulo_id: articuloId },
      { withCredentials: true } // Necesario para enviar cookies/sesiones
    )
    .then(response => {
      // Procesamiento de la respuesta
    })
    .catch(error => {
      console.error('Error al procesar el like:', error);
    });
  };

  return (
    <div className="flex items-center mt-6">
      <Button onClick={handleLike} color={liked ? 'pink' : 'gray'} className="flex items-center">
        <FiHeart className="mr-2" />
        {liked ? 'Te Gusta' : 'Me Gusta'}
      </Button>
      <span className="ml-4 text-gray-600 dark:text-gray-400">
        {totalLikes} {totalLikes === 1 ? 'Me Gusta' : 'Me Gustas'}
      </span>
    </div>
  );
}

export default LikeButton;
```

## File: frontend/react-app/src/components/Navbar.js
```javascript
// src/components/Navbar.js

import React, { useContext, useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Link as ScrollLink } from 'react-scroll';
import { AuthContext } from '../context/AuthContext';
import { DarkModeToggle } from './DarkModeToggle';
import logo from '../assets/Yo.jpeg';

function NavigationBar() {
  const { authData } = useContext(AuthContext);
  const location = useLocation();
  const [menuOpen, setMenuOpen] = useState(false);

  return (
    <nav className="bg-white dark:bg-gray-800 fixed w-full z-20 top-0 left-0 border-b border-gray-200 dark:border-gray-600">
      <div className="max-w-screen-xl mx-auto px-4">
        <div className="flex justify-between items-center h-16">
          {/* Sección Izquierda: Logo */}
          <Link to="/" className="flex items-center">
            <img src={logo} className="h-8 w-auto mr-2" alt="Logo" />
            <span className="text-xl font-semibold text-gray-900 dark:text-white">
              Yisus Price
            </span>
          </Link>

          {/* Sección Central: Enlaces de navegación */}
          <div className="hidden md:flex space-x-6">
            <Link
              to="/"
              className={`text-gray-900 dark:text-white hover:underline ${
                location.pathname === '/' ? 'font-bold' : ''
              }`}
            >
              Inicio
            </Link>
            <Link
              to="/noticias"
              className={`text-gray-900 dark:text-white hover:underline ${
                location.pathname === '/noticias' ? 'font-bold' : ''
              }`}
            >
              Noticias
            </Link>
            <ScrollLink
              to="youtube"
              smooth={true}
              duration={500}
              offset={-80}
              className="cursor-pointer text-gray-900 dark:text-white hover:underline"
              activeClass="font-bold"
              spy={true}
            >
              YouTube
            </ScrollLink>
            <ScrollLink
              to="videos"
              smooth={true}
              duration={500}
              offset={-80}
              className="cursor-pointer text-gray-900 dark:text-white hover:underline"
              activeClass="font-bold"
              spy={true}
            >
              Videos
            </ScrollLink>
            <ScrollLink
              to="sobre-mi"
              smooth={true}
              duration={500}
              offset={-80}
              className="cursor-pointer text-gray-900 dark:text-white hover:underline"
              activeClass="font-bold"
              spy={true}
            >
              Sobre Mí
            </ScrollLink>
            <ScrollLink
              to="contacto"
              smooth={true}
              duration={500}
              offset={-80}
              className="cursor-pointer text-gray-900 dark:text-white hover:underline"
              activeClass="font-bold"
              spy={true}
            >
              Contacto
            </ScrollLink>
          </div>

          {/* Sección Derecha: Enlaces de autenticación y modo oscuro */}
          <div className="flex items-center space-x-4">
            {authData ? (
              <Link
                to="/perfil"
                className="text-gray-900 dark:text-white hover:underline"
              >
                Perfil
              </Link>
            ) : (
              <>
                <Link to="/registro">
                  <button className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
                    Registrarse
                  </button>
                </Link>
                <Link to="/login">
                  <button className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
                    Iniciar Sesión
                  </button>
                </Link>
              </>
            )}
            <DarkModeToggle />
          </div>

          {/* Botón de menú móvil */}
          <div className="md:hidden">
            <button
              className="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none"
              onClick={() => setMenuOpen(!menuOpen)}
            >
              <svg
                className="h-6 w-6"
                stroke="currentColor"
                fill="none"
                viewBox="0 0 24 24"
              >
                {menuOpen ? (
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth="2"
                    d="M6 18L18 6M6 6l12 12"
                  />
                ) : (
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth="2"
                    d="M4 6h16M4 12h16M4 18h16"
                  />
                )}
              </svg>
            </button>
          </div>
        </div>
      </div>

      {/* Menú desplegable para móviles */}
      {menuOpen && (
        <div className="md:hidden">
          <div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
            <Link
              to="/"
              className="block text-gray-700 dark:text-gray-300 px-3 py-2 rounded-md text-base font-medium"
              onClick={() => setMenuOpen(false)}
            >
              Inicio
            </Link>
            <Link
              to="/noticias"
              className="block text-gray-700 dark:text-gray-300 px-3 py-2 rounded-md text-base font-medium"
              onClick={() => setMenuOpen(false)}
            >
              Noticias
            </Link>
            <ScrollLink
              to="youtube"
              smooth={true}
              duration={500}
              offset={-80}
              className="block cursor-pointer text-gray-700 dark:text-gray-300 px-3 py-2 rounded-md text-base font-medium"
              activeClass="font-bold"
              spy={true}
              onClick={() => setMenuOpen(false)}
            >
              YouTube
            </ScrollLink>
            <ScrollLink
              to="videos"
              smooth={true}
              duration={500}
              offset={-80}
              className="block cursor-pointer text-gray-700 dark:text-gray-300 px-3 py-2 rounded-md text-base font-medium"
              activeClass="font-bold"
              spy={true}
              onClick={() => setMenuOpen(false)}
            >
              Videos
            </ScrollLink>
            <ScrollLink
              to="sobre-mi"
              smooth={true}
              duration={500}
              offset={-80}
              className="block cursor-pointer text-gray-700 dark:text-gray-300 px-3 py-2 rounded-md text-base font-medium"
              activeClass="font-bold"
              spy={true}
              onClick={() => setMenuOpen(false)}
            >
              Sobre Mí
            </ScrollLink>
            <ScrollLink
              to="contacto"
              smooth={true}
              duration={500}
              offset={-80}
              className="block cursor-pointer text-gray-700 dark:text-gray-300 px-3 py-2 rounded-md text-base font-medium"
              activeClass="font-bold"
              spy={true}
              onClick={() => setMenuOpen(false)}
            >
              Contacto
            </ScrollLink>
            {authData ? (
              <Link
                to="/perfil"
                className="block text-gray-700 dark:text-gray-300 px-3 py-2 rounded-md text-base font-medium"
                onClick={() => setMenuOpen(false)}
              >
                Perfil
              </Link>
            ) : (
              <>
                <Link to="/registro" onClick={() => setMenuOpen(false)}>
                  <button className="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
                    Registrarse
                  </button>
                </Link>
                <Link to="/login" onClick={() => setMenuOpen(false)}>
                  <button className="w-full mt-2 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
                    Iniciar Sesión
                  </button>
                </Link>
              </>
            )}
          </div>
        </div>
      )}
    </nav>
  );
}

export default NavigationBar;
```

## File: frontend/react-app/src/components/Preloader.js
```javascript
// src/components/Preloader.js
import React from 'react';

function Preloader() {
  return (
    <div className="fixed inset-0 flex items-center justify-center bg-white dark:bg-gray-900 z-50">
      <svg
        className="animate-spin h-16 w-16 text-purple-500 dark:text-purple-800"
        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="M12 2a10 10 0 0110 10h-4a6 6 0 00-6-6V2z"
        ></path>
      </svg>
    </div>
  );
}

export default Preloader;
```

## File: frontend/react-app/src/components/ScrollToTopButton.js
```javascript
// src/components/ScrollToTopButton.js
import React, { useState, useEffect } from 'react';
import { FaArrowUp } from 'react-icons/fa';

function ScrollToTopButton() {
  const [isVisible, setIsVisible] = useState(false);

  // Mostrar el botón cuando el usuario haya bajado 300px
  const toggleVisibility = () => {
    if (window.pageYOffset > 300) {
      setIsVisible(true);
    } else {
      setIsVisible(false);
    }
  };

  // Función de desplazamiento personalizado
  const scrollToTop = () => {
    const start = window.pageYOffset;
    const duration = 1000; // Duración de la animación en milisegundos
    let startTime = null;

    // Función de aceleración (easing function)
    const easeInOutQuad = (t, b, c, d) => {
      t /= d / 2;
      if (t < 1) return (c / 2) * t * t + b;
      t--;
      return (-c / 2) * (t * (t - 2) - 1) + b;
    };

    const animateScroll = (currentTime) => {
      if (startTime === null) startTime = currentTime;
      const timeElapsed = currentTime - startTime;
      const run = easeInOutQuad(timeElapsed, start, -start, duration);
      window.scrollTo(0, run);
      if (timeElapsed < duration) requestAnimationFrame(animateScroll);
    };

    requestAnimationFrame(animateScroll);
  };

  useEffect(() => {
    window.addEventListener('scroll', toggleVisibility);

    return () => {
      window.removeEventListener('scroll', toggleVisibility);
    };
  }, []);

  return (
    <div className="fixed bottom-8 right-8">
      {/* Aplicamos las clases condicionales para la animación suave */}
      <button
        onClick={scrollToTop}
        className={`p-3 rounded-full bg-purple-500 text-white shadow-md hover:bg-purple-600 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-opacity-50 transition-opacity duration-300 ${
          isVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'
        }`}
      >
        <FaArrowUp size={24} />
      </button>
    </div>
  );
}

export default ScrollToTopButton;
```

## File: frontend/react-app/src/components/VideoCarousel.js
```javascript
// src/components/VideoCarousel.js
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination } from 'swiper/modules';

import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';

function VideoCarousel() {
  const videos = [
    {
      url: 'https://www.youtube.com/embed/-HMODGh8nE4?si=vniGQZoGBtxJ5CrA',
      titulo: 'Título del Video 1',
    },
    {
      url: 'https://www.youtube.com/embed/AvxhYmyy2t8?si=S8gcSucS6cwSyKEr',
      titulo: 'Título del Video 2',
    },
    {
      url: 'https://www.youtube.com/embed/_d84xD8v0nM?si=RvuA7OWrK-qIzjqn',
      titulo: 'Título del Video 3',
    },
    // Agrega más videos si lo deseas
  ];

  return (
    <div className="mx-auto max-w-md"> {/* Añade este div contenedor */}
    <Swiper
      modules={[Navigation, Pagination]}
      spaceBetween={20}
      slidesPerView={1}
      navigation
      pagination={{ clickable: true }}
      breakpoints={{
        640: { slidesPerView: 1 },
        768: { slidesPerView: 1 },
        1024: { slidesPerView: 1 },
      }}
    >
      {videos.map((video, index) => (
        <SwiperSlide key={index}>
          <div className="relative pb-[56.25%]"> {/* 16:9 Aspect Ratio */}
            <iframe
              src={video.url}
              title={video.titulo}
              frameBorder="0"
              allowFullScreen
              className="absolute top-0 left-0 w-full h-full"
            ></iframe>
          </div>
        </SwiperSlide>
      ))}
    </Swiper>
    </div>
  );
  
}

export default VideoCarousel;
```