frontend pilotos

This commit is contained in:
Tatiana Villa Ema 2026-02-22 23:44:26 +01:00
parent 9b7c1b85c4
commit 0b0783b173
7 changed files with 434 additions and 228 deletions

74
css/f1.css Normal file
View File

@ -0,0 +1,74 @@
:root {
--f1-red: #a00000;
--dark-bg: #15151e;
--card-bg: #1f1f27;
--text: #ffffff;
--border-color: #38383f;
--titulo-color: #ff4c4c;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--dark-bg);
color: var(--text);
margin: 0;
padding: 20px;
}
header {
padding-bottom: 10px;
margin-bottom: 30px;
text-align: center;
color: var(--titulo-color);
}
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.stat-card {
background-color: var(--card-bg);
padding: 20px;
border-radius: 10px;
border-left: 4px solid var(--f1-red);
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th, td {
text-align: left;
padding: 8px;
border-bottom: 1px solid var(--border-color);
}
th {
color: var(--titulo-color);
font-size: 0.8rem;
text-transform: uppercase;
}
.pos {
font-weight: bold;
color: var(--f1-red);
}
.cuenta-atras {
margin-bottom: 15px;
text-align: center;
border-bottom: 4px solid var(--f1-red);
}
#countdown {
font-size: 2rem;
font-weight: bold;
letter-spacing: 2px;
}

59
f1.html Normal file
View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>F1 Stats Pro - Panel de Control</title>
<link rel="stylesheet" href="css/f1.css">
</head>
<body>
<header>
<h1>Estadísticas F1</h1>
</header>
<section class="stat-card cuenta-atras">
<h3 > Cuenta atrás para el GP de Australia 2026</h3>
<div id="countdown">
00d 00h 00m 00s
</div>
</section>
<main class="dashboard">
<section class="stat-card">
<h3 id="session-info">Cargando sesión...</h3>
<div id="api-status">Buscando señal...</div>
<table>
<thead>
<tr>
<th></th>
<th>Piloto</th>
<th>Escudería</th>
<th>Siglas</th>
</tr>
</thead>
<tbody id="tabla-pilotos-body">
</tbody>
</table>
</section>
<section class="stat-card">
<h3>Telemetría en Vivo (Sector 1)</h3>
<p>Velocidad Punta: <strong>334 km/h</strong></p>
<p>Estado de Pista: <strong>Seco</strong></p>
<p>Récord de vuelta: <strong>1:16.623</strong></p>
</section>
<section class="stat-card" style="border-left-color: var(--f1-red);">
<h3>Admin Info (Debug)</h3>
<ul>
<li>DB: PostgreSQL 15</li>
<li>API Status: Online</li>
<li>Last Backup: 02:00 AM</li>
</ul>
</section>
</main>
<script src="js/f1.js"></script>
</body>
</html>

View File

@ -1,132 +1,103 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tatiana Villa</title>
<link rel="icon" href="img/tatianalogo.png" type="image/x-icon">
<!-- Estilos -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aplicaciones de Vanguardia</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/sobremi.css">
<link rel="stylesheet" href="css/style.css">
<link rel="icon" href="favicon.ico" type="image/x-icon">
</head>
<body class="bg-black text-light">
<!-- Header -->
<!-- Header -->
<header>
<nav class="navbar navbar-expand-sm navbar-dark bg-dark shadow-sm border-bottom border-secondary">
<div class="container-fluid">
<!-- Logo -->
<a class="navbar-brand font-weight-bold" href="index.html" style="font-family: 'Consolas', monospace;">
<span class="text-primary">{</span>Tatiana Villa <span class="text-primary">}</span>
<span class="text-primary">{</span>Aplicaciones de Vanguardia <span class="text-primary">}</span>
</a>
<!-- Botón móvil -->
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menuNav"
aria-controls="menuNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Menú -->
<div class="collapse navbar-collapse justify-content-end" id="menuNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="index.html">Inicio</a>
</li>
<li class="nav-item">
<a class="nav-link" href="proyectos.html">Proyectos</a>
</li>
<li class="nav-item">
<a class="nav-link" href="habilidades.html">Habilidades</a>
</li>
<!--
<li class="nav-item">
<a class="nav-link" href="formacion.html">Formación</a>
</li>
<li class="nav-item">
<a class="nav-link" href="experiencia.html">Experiencia</a>
</li>
-->
</ul>
</div>
</div>
</nav>
</header>
<!-- Main Content -->
<main class="container main-content py-5">
<p class="text-success h5 font-monospace">
/** <br>
* Hola, soy Tatiana Villa Ema <!--(<span id="edad"></span> años)--> <br>
* Full Stack Developer<br>
*/
</p>
<div class="row mt-4">
<div class="col-md-8">
<h3 class="text-primary">&lt;sobre-mi&gt;</h3>
<p>Mi camino en tecnología empezó muy pronto. Desde joven me formé en informática y comencé mi carrera profesional en entornos de alto nivel, trabajando como programadora y administradora de <span class="habilidad">sistemas Unix/Linux</span> para empresas como <span class="empresa">Hewlett-Packard, Telefónica, Caja Duero, Oracle o Realia</span>. Durante más de una década gestioné infraestructuras críticas, impartí formación técnica y resolví problemas complejos en <span class="habilidad"> Linux y HP-UX</span>, siempre con un enfoque práctico, metódico y orientado a la estabilidad.</p>
<p>Cuando nacieron mis hijos decidí priorizar mi familia y hacer una pausa en mi carrera profesional. Fue una etapa importante y necesaria, pero nunca dejé de sentir que la tecnología seguía siendo mi lugar. Ahora mismo mi hija mayor tiene <span id="edad-andrea"></span> años y mis hijos mellizos tienen <span id="edad-gemelos"></span> años.</p>
<p>Poco antes de la pandemia (hace ya <span id="edad-pandemia"></span> años) intenté reincorporarme al sector, pero por ser persona de riesgo tuve que aislarme. Ese parón inesperado se convirtió en una oportunidad: retomé mi formación desde cero, actualicé mis conocimientos y me abrí a nuevas áreas. Estudié <span class="curso">Administracion y diseño de redes departamentales</span>,<span class="curso"> desarrollo de aplicaciones web</span>, <span class="curso">robótica con arduino</span>, <span class="curso">diseño 3D</span> y, finalmente, completé el título de <span class="curso">FPGS Desarrollo de Aplicaciones Multiplataforma (DAM)</span>.</p>
<p>Desde entonces he seguido creciendo como desarrolladora Full Stack, reforzando mi base en <span class="habilidad">Java, PHP, JavaScript, HTML, CSS, Spring, Hibernate, MySQL, .NET</span>, <span class="habilidad">DevOps</span> y <span class="habilidad">Cloud</span>.</p>
<p>Hoy combino mi experiencia en sistemas con mi formación en desarrollo para crear soluciones completas, estables y bien pensadas. Mi trayectoria no es lineal, y precisamente por eso es valiosa: sé cómo funcionan las cosas por dentro, sé cómo construirlas por fuera y sé adaptarme, aprender y reinventarme cuando la vida lo exige.</p>
<section id="proyectos" class="py-5">
<div class="container py-5">
<h2 class="section-title mb-5">Proyectos en desarrollo</h2>
<h3 class="text-primary">&lt;/sobre-mi&gt;</h3>
</div>
<div class="row g-4">
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">Recursos Católicos</h5>
<p class="card-text text-muted">Web de recursos católicos gratuitos (Rosario, oraciones, etc.).</p>
<p class="card-text text-muted card-tecnologia">HTML, CSS, Bootstrap, JavaScript, PHP, SQL, XML, JSON.</p>
<a href="https://recursos-catolicos.es" class="btn-link">Saber más →</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card bg-dark border-secondary p-3 shadow">
<h5 class="text-info">// Conocimientos</h5>
<ul class="list-unstyled mb-0">
<li class="mb-2 card-text">Java, Spring, Hibernate</li>
<li class="mb-2 card-text">PHP, JavaScript, HTML, CSS, Bootstrap</li>
<li class="mb-2 card-text">C#, .NET, SQL, Docker</li>
<li class="mb-2 card-text">Linux, HP-UX, DevOps, VMware</li>
<li class="mb-2 card-text">Cloud (Azure)</li>
<li class="mb-2 card-text">Diseño 3D, robótica con Arduino</li>
<li class="mb-2 card-text">Desarrollo de videojuegos con Unity</li>
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
</ul>
<div class="card-body">
<h5 class="card-title fw-bold">El Tiempo</h5>
<p class="card-text text-muted">Guardo los datos del tiempo de 3 ciudades españolas que me interesan (Madrid, L'Ampolla (Tarragona), L'Alfas del Pi (Alicante)) con fines estadísticos. </p>
<p class="card-text text-muted card-tecnologia">PHP, MySQL, HTML, CSS, JavaScript.</p>
<a href="eltiempo/index.html" class="btn-link">Saber más →</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">Oposiciones</h5>
<p class="card-text text-muted">Temario y cuestionarios para TAI AGE</p>
<p class="card-text text-muted card-tecnologia">HTML, CSS</p>
<a href="oposiciones/index.html" class="btn-link">Saber más →</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">Piedra, Papel o Tijera</h5>
<p class="card-text text-muted">El famoso juego Piedra, Papel o Tijera.</p>
<p class="card-text text-muted card-tecnologia">HTML, CSS, JavaScript y optimizado para dispositivos móviles.</p>
<a href="piedra-papel-tijera.html" class="btn-link">Saber más →</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">F1</h5>
<p class="card-text text-muted">Pronosticos, estadisticas, resultados y noticias de Fórmula 1.</p>
<p class="card-text text-muted card-tecnologia">HTML, CSS, JavaScript y optimizado para dispositivos móviles.</p>
<a href="f1.html" class="btn-link">Saber más →</a>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="col-md-4">
<div class="card bg-dark border-secondary p-3 shadow">
<h5 class="text-info">// Habilidades</h5>
<ul class="list-unstyled mb-0">
<li class="mb-2 card-text">Trabajo en equipo, resolución de conflictos</li>
</ul>
</div>
</div>
</div>
</main>
<footer class="py-5 text-center">
<footer class="py-5 text-center">
<div class="container">
<p class="mb-0">&copy; <span id="anio"></span> - Tatiana Villa</p>
<p class="mb-0">&copy; 2026 - Tatiana Villa</p>
</div>
</footer>
<!--
<script>
document.getElementById("anio").textContent = new Date().getFullYear();
</script>
-->
<script src="js/codigo.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

91
js/f1.js Normal file
View File

@ -0,0 +1,91 @@
// ===============================
// FUNCIONES DE CONSULTA API
// https://ergast.com/mrd/overview/f1/
// ===============================
async function obtenerCalendario() {
// Cargar la programación completa de la actual temporada
const response = await fetch("https://api.jolpi.ca/ergast/f1/current.json");
const data = await response.json();
const carreras = data.MRData.RaceTable.Races;
return carreras;
}
function encontrarSiguienteCarrera(carreras) {
const ahora = new Date();
for (let carrera of carreras) {
const fecha = new Date(`${carrera.date}T${carrera.time || '00:00:00Z'}`);
if (fecha > ahora) {
return { ...carrera, fecha };
}
}
return null;
}
// ===============================
// CUENTA ATRÁS DINÁMICA
// ===============================
function iniciarCuentaAtras(fechaCarrera) {
const countdown = document.getElementById("countdown");
function actualizar() {
const ahora = new Date();
const diff = fechaCarrera - ahora;
if (diff <= 0) {
countdown.textContent = "🏁 ¡La carrera empezó!";
return;
}
const dias = Math.floor(diff / (1000 * 60 * 60 * 24));
const horas = Math.floor((diff / (1000 * 60 * 60)) % 24);
const minutos = Math.floor((diff / (1000 * 60)) % 60);
const segundos = Math.floor((diff / 1000) % 60);
countdown.textContent = `${dias}d ${horas}h ${minutos}m ${segundos}s`;
}
actualizar();
setInterval(actualizar, 1000);
}
// ===============================
// INIT PRINCIPAL
// ===============================
async function init() {
// 1) Obtener calendario
const carreras = await obtenerCalendario();
// 2) Calcular siguiente evento
const proxima = encontrarSiguienteCarrera(carreras);
if (!proxima) {
document.getElementById("countdown").textContent =
"No hay próximos Grandes Premios este año";
return;
}
// Mostramos el nombre de la próxima carrera
document.querySelector(".cuenta-atras h3").textContent =
`Cuenta atrás para el GP de ${proxima.raceName}`;
// 3) Poner la cuenta atrás
iniciarCuentaAtras(proxima.fecha);
// 4) Si estamos en fin de semana de carrera o justo comienza
const ahora = new Date();
if (ahora >= proxima.fecha) {
// Aquí puedes pedir sesiones o tiempos reales si la API lo soporta
console.log("Estamos en modo carrera");
document.getElementById("session-info").textContent =
"Modo carrera — datos en vivo o resultados";
} else {
// Modo pronóstico/previo
console.log("Estamos antes del fin de semana de carrera");
document.getElementById("session-info").textContent =
`Próxima sesión de ${proxima.raceName}`;
}
}
document.addEventListener("DOMContentLoaded", init);

49
js/f1pruebas.js Normal file
View File

@ -0,0 +1,49 @@
const BASE_URL = 'https://api.openf1.org/v1';
async function cargarDatosF1() {
const statusDiv = document.getElementById('api-status');
const tablaCuerpo = document.getElementById('tabla-pilotos-body');
try {
statusDiv.innerHTML = 'Conectando con OpenF1...';
// Usamos una session_key fija de un GP pasado para probar que funciona
// Bahrain 2024 Session Key: 9465
const sessionKey = '9465';
document.getElementById('session-info').innerText = "GP de Bahrain (Datos de Test)";
const driversRes = await fetch(`${BASE_URL}/drivers?session_key=${sessionKey}`);
if (!driversRes.ok) throw new Error(`Error HTTP: ${driversRes.status}`);
const drivers = await driversRes.json();
if (drivers.length === 0) {
statusDiv.innerHTML = 'No se encontraron pilotos.';
return;
}
tablaCuerpo.innerHTML = '';
drivers.forEach(driver => {
const row = document.createElement('tr');
row.innerHTML = `
<td style="border-left: 4px solid #${driver.team_colour || 'ccc'}">
${driver.driver_number}
</td>
<td><strong>${driver.full_name}</strong></td>
<td>${driver.team_name}</td>
<td>${driver.name_acronym}</td>
`;
tablaCuerpo.appendChild(row);
});
statusDiv.innerHTML = '<span style="color: #4caf50;">● Datos cargados con éxito</span>';
} catch (error) {
console.error("DETALLE DEL ERROR:", error);
statusDiv.innerHTML = `<span style="color: #ff4b4b;">● Error: ${error.message}</span>`;
}
}
document.addEventListener('DOMContentLoaded', cargarDatosF1);

89
pilotos.html Normal file
View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pilotos de F1</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f7f7f7;
padding: 20px;
}
h1 {
text-align: center;
color: #333;
}
table {
margin: 0 auto;
border-collapse: collapse;
width: 90%;
max-width: 800px;
background-color: white;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
th, td {
padding: 10px 15px;
border: 1px solid #ddd;
text-align: center;
}
th {
background-color: #004080;
color: white;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
tr:hover {
background-color: #cce0ff;
}
</style>
</head>
<body>
<h1>Pilotos de F1</h1>
<table id="pilotos-table">
<thead>
<tr>
<th>#</th>
<th>Nombre</th>
<th>Apellido</th>
<th>Equipo</th>
<th>Nacionalidad</th>
<th>Código</th>
</tr>
</thead>
<tbody>
<!-- Aquí se llenarán los pilotos -->
</tbody>
</table>
<script>
async function cargarPilotos() {
try {
const response = await fetch('/f1/api/pilotos');
const pilotos = await response.json();
const tbody = document.querySelector('#pilotos-table tbody');
pilotos.forEach(p => {
const fila = document.createElement('tr');
fila.innerHTML = `
<td>${p.numero}</td>
<td>${p.nombre}</td>
<td>${p.apellido}</td>
<td>${p.equipo || '-'}</td>
<td>${p.nacionalidad}</td>
<td>${p.codigo}</td>
`;
tbody.appendChild(fila);
});
} catch (error) {
console.error('Error cargando pilotos:', error);
const tbody = document.querySelector('#pilotos-table tbody');
tbody.innerHTML = `<tr><td colspan="6">No se pudieron cargar los pilotos</td></tr>`;
}
}
cargarPilotos();
</script>
</body>
</html>

View File

@ -1,127 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aplicaciones de Vanguardia</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/style.css">
<link rel="icon" href="favicon.ico" type="image/x-icon">
</head>
<body class="bg-black text-light">
<!-- Header -->
<header>
<nav class="navbar navbar-expand-sm navbar-dark bg-dark shadow-sm border-bottom border-secondary">
<div class="container-fluid">
<!-- Logo -->
<a class="navbar-brand font-weight-bold" href="index.html" style="font-family: 'Consolas', monospace;">
<span class="text-primary">{</span>Tatiana Villa <span class="text-primary">}</span> Proyectos
</a>
<!-- Botón móvil -->
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menuNav"
aria-controls="menuNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Menú -->
<div class="collapse navbar-collapse justify-content-end" id="menuNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="index.html">Inicio</a>
</li>
<li class="nav-item">
<a class="nav-link" href="proyectos.html">Proyectos</a>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="habilidades.html">Habilidades</a>
</li>
<!--
<li class="nav-item">
<a class="nav-link" href="formacion.html">Formación</a>
</li>
<li class="nav-item">
<a class="nav-link" href="experiencia.html">Experiencia</a>
</li>
-->
</ul>
</div>
</div>
</nav>
</header>
<section id="proyectos" class="py-5">
<div class="container py-5">
<h2 class="section-title mb-5">Proyectos</h2>
<div class="row g-4">
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">Recursos Católicos</h5>
<p class="card-text text-muted">Web de recursos católicos gratuitos (Rosario, oraciones, etc.).</p>
<p class="card-text text-muted card-tecnologia">HTML, CSS, Bootstrap, JavaScript, PHP, SQL, XML, JSON.</p>
<a href="https://recursos-catolicos.es" class="btn-link">Saber más →</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">El Tiempo</h5>
<p class="card-text text-muted">Guardo los datos del tiempo de 3 ciudades españolas que me interesan (Madrid, L'Ampolla (Tarragona), L'Alfas del Pi (Alicante)) con fines estadísticos. </p>
<p class="card-text text-muted card-tecnologia">PHP, MySQL, HTML, CSS, JavaScript.</p>
<a href="eltiempo/index.html" class="btn-link">Saber más →</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">Oposiciones</h5>
<p class="card-text text-muted">Temario y cuestionarios para TAI AGE</p>
<p class="card-text text-muted card-tecnologia">HTML, CSS</p>
<a href="oposiciones/index.html" class="btn-link">Saber más →</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="card project-card h-100">
<div class="card-body">
<h5 class="card-title fw-bold">Piedra, Papel o Tijera</h5>
<p class="card-text text-muted">El famoso juego Piedra, Papel o Tijera.</p>
<p class="card-text text-muted card-tecnologia">HTML, CSS, JavaScript y optimizado para dispositivos móviles.</p>
<a href="piedra-papel-tijera.html" class="btn-link">Saber más →</a>
</div>
</div>
</div>
</div>
</div>
</section>
<footer class="py-5 text-center">
<div class="container">
<p class="mb-0">&copy; 2026 - Tatiana Villa</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>