Merge branch 'main' of github.com:tatvil/portfolio2026

This commit is contained in:
Tatiana Villa 2026-03-09 19:08:56 +01:00
commit 34d4040fb5
14 changed files with 840 additions and 30 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;
}

View File

@ -46,6 +46,7 @@ html, body {
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
<<<<<<< HEAD
.empresa {
color: var(--keyword);
}
@ -59,6 +60,8 @@ html, body {
}
=======
>>>>>>> 1409b91efed570aae51e1eaf845151685bb4f177
/* 4. ESTILOS DE CÓDIGO (COLORES) */
.text-primary {
color: var(--keyword) !important;

View File

@ -184,4 +184,11 @@ footer {
text-decoration: none;
font-weight: bold;
transition: 0.3s;
}
.timeline {
background-color: var(--color-tarjeta);
border-left: 1px solid var(--color-primario);
margin-bottom: 1.5rem;
transition: 0.3s;
}

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<title>Estadísticas | El Tiempo</title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="/img/tatianalogo.png" type="image/x-icon">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/estilos.css">
</head>

View File

@ -9,23 +9,19 @@ const monthNames = ["Enero","Febrero","Marzo","Abril","Mayo","Junio",
let selectedMonth = new Date().getMonth(); // mes actual
let ciudadActual = "Madrid"; // ciudad por defecto
const BASE_API = "https://aplicacionesdevanguardia.es/eltiempo/servidor/api-weather-fechas.php";
// const BASE_API = "https://aplicacionesdevanguardia.es/eltiempo/servidor/api-weather-fechas.php";
const BASE_API = "https://tatvil.es/apis/api/weather/filter";
// ====================
// Construir URL de API según filtros
// ====================
function buildApiUrl({ ciudad, fecha = null, desde = null, hasta = null }) {
function buildApiUrl({ ciudad, desde, hasta }) {
const params = new URLSearchParams();
params.append("ciudad", ciudad);
if (fecha) params.append("fecha", fecha);
if (desde) params.append("desde", desde);
if (hasta) params.append("hasta", hasta);
console.log("24 - Construyendo URL con parámetros:", { ciudad, fecha, desde, hasta });
params.append("desde", desde);
params.append("hasta", hasta);
console.log("Construyendo URL con parámetros:", { ciudad, desde, hasta });
console.log("URL API:", `${BASE_API}?${params.toString()}`);
return `${BASE_API}?${params.toString()}`;
}
// ====================
@ -40,17 +36,18 @@ function updateMonthHeader() {
// ====================
async function loadStats(options = {}) {
try {
const url = buildApiUrl({
ciudad: ciudadActual,
...options
});
const url = buildApiUrl({ ciudad: ciudadActual, ...options });
const response = await fetch(url);
if (!response.ok) throw new Error("Error cargando datos: " + response.status);
const data = await response.json();
let data = await response.json(); // Cambia 'const' por 'let'
if (!data || !data.length) throw new Error("Datos vacíos");
// --- FILTRADO POR CIUDAD (Importante mientras Java no filtre) ---
data = data.filter(d => d.ciudad === ciudadActual);
// ----------------------------------------------------------------
renderLastData(data);
renderMonthStats(data);
renderTrend(data);
@ -115,10 +112,17 @@ function getMoonPhase() {
// Estadísticas del mes seleccionado
// ====================
function renderMonthStats(data) {
const monthData = data.filter(d => new Date(d.dia).getMonth() === selectedMonth);
if (!monthData.length) return;
// Esta es la clave: filtrar por el mes seleccionado antes de calcular
const monthData = data.filter(d => {
const fechaDato = new Date(d.dia);
return fechaDato.getMonth() === selectedMonth;
});
if (!monthData.length) {
// Si no hay datos, ponemos a cero para que no salgan cosas raras
$("month-days").textContent = 0;
return;
}
const maxTemps = monthData.map(d => d.temp_max);
const minTemps = monthData.map(d => d.temp_min);
const lluvia = monthData.reduce((sum, d) => sum + parseFloat(d.lluvia), 0);

View File

@ -0,0 +1,251 @@
// ====================
// Helper
// ====================
function $(id) { return document.getElementById(id); }
const monthNames = ["Enero","Febrero","Marzo","Abril","Mayo","Junio",
"Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"];
let selectedMonth = new Date().getMonth(); // mes actual
let ciudadActual = "Madrid"; // ciudad por defecto
const BASE_API = "https://aplicacionesdevanguardia.es/eltiempo/servidor/api-weather-fechas.php";
// ====================
// Construir URL de API según filtros
// ====================
function buildApiUrl({ ciudad, fecha = null, desde = null, hasta = null }) {
const params = new URLSearchParams();
params.append("ciudad", ciudad);
if (fecha) params.append("fecha", fecha);
if (desde) params.append("desde", desde);
if (hasta) params.append("hasta", hasta);
console.log("24 - Construyendo URL con parámetros:", { ciudad, fecha, desde, hasta });
console.log("URL API:", `${BASE_API}?${params.toString()}`);
return `${BASE_API}?${params.toString()}`;
}
// ====================
// Actualizar nombre de mes
// ====================
function updateMonthHeader() {
$("mes-nombre").textContent = monthNames[selectedMonth];
}
// ====================
// Cargar datos desde la API
// ====================
async function loadStats(options = {}) {
try {
const url = buildApiUrl({
ciudad: ciudadActual,
...options
});
const response = await fetch(url);
if (!response.ok) throw new Error("Error cargando datos: " + response.status);
const data = await response.json();
if (!data || !data.length) throw new Error("Datos vacíos");
renderLastData(data);
renderMonthStats(data);
renderTrend(data);
} catch (err) {
console.error(err);
$("stats-location").textContent = "Error cargando datos";
}
}
// ====================
// Último dato
// ====================
function renderLastData(data) {
const last = data[data.length - 1];
$("last-date").textContent = last.dia;
$("last-temp").textContent = last.temp_max + "°C / " + last.temp_min + "°C";
$("last-humidity").textContent = last.humedad + " %";
$("last-rain").textContent = last.lluvia + " mm";
$("last-wind").textContent = last.viento_velocidad + " km/h";
$("last-sunrise").textContent = last.amanecer;
$("last-sunset").textContent = last.anochecer;
$("stats-location").textContent = `Estadisticas de ${ciudadActual}`;
}
// ====================
// FASES LUNARES
// ====================
function getMoonPhase() {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1;
const day = now.getDate();
const c = Math.floor(365.25 * year);
const e = Math.floor(30.6 * (month + 1));
const jd = c + e + day - 694039.09;
const phase = (jd / 29.53) % 1;
const age = phase * 29.53;
let phaseName = "", icon = "";
if (age < 1.84566) { phaseName = "Luna Nueva"; icon = "🌑"; }
else if (age < 5.53699) { phaseName = "Creciente Iluminante"; icon = "🌒"; }
else if (age < 9.22831) { phaseName = "Cuarto Creciente"; icon = "🌓"; }
else if (age < 12.91963) { phaseName = "Gibosa Creciente"; icon = "🌔"; }
else if (age < 16.61096) { phaseName = "Luna Llena"; icon = "🌕"; }
else if (age < 20.30228) { phaseName = "Gibosa Menguante"; icon = "🌖"; }
else if (age < 23.99361) { phaseName = "Cuarto Menguante"; icon = "🌗"; }
else if (age < 27.68493) { phaseName = "Creciente Menguante"; icon = "🌘"; }
else { phaseName = "Luna Nueva"; icon = "🌑"; }
$("moon-phase").textContent = phaseName;
$("moon-icon").textContent = icon;
const today = new Date();
$("stats-location").textContent += ` | Hoy ${today.getDate()} de ${monthNames[today.getMonth()]} de ${today.getFullYear()}`;
}
// ====================
// Estadísticas del mes seleccionado
// ====================
function renderMonthStats(data) {
const monthData = data.filter(d => new Date(d.dia).getMonth() === selectedMonth);
if (!monthData.length) return;
const maxTemps = monthData.map(d => d.temp_max);
const minTemps = monthData.map(d => d.temp_min);
const lluvia = monthData.reduce((sum, d) => sum + parseFloat(d.lluvia), 0);
const humedad = (monthData.reduce((sum, d) => sum + parseFloat(d.humedad), 0) / monthData.length).toFixed(1);
const lluviamedia = lluvia/monthData.length; // media de lluvia diaria
$("month-days").textContent = monthData.length;
$("month-max").textContent = Math.max(...maxTemps) + "°C";
$("month-min").textContent = Math.min(...minTemps) + "°C";
$("month-rain").textContent = lluvia.toFixed(1) + " mm (total) / " + lluviamedia.toFixed(1) + " mm (media diaria)";
$("month-humidity").textContent = humedad + " % (media diaria)";
}
// ====================
// Tendencia histórica
// ====================
function renderTrend(data) {
const byYear = {};
console.log("Datos recibidos para tendencia histórica:", data);
// Agrupar datos por año para el mes seleccionado
data.forEach(d => {
const date = new Date(d.dia);
if (date.getMonth() === selectedMonth) {
const year = date.getFullYear();
if (!byYear[year]) byYear[year] = { max: [], min: [], rain: [] };
byYear[year].max.push(d.temp_max);
byYear[year].min.push(d.temp_min);
byYear[year].rain.push(parseFloat(d.lluvia));
}
});
const container = $("trend-container");
console.log("Datos agrupados por año para tendencia:", byYear);
if (Object.keys(byYear).length === 0) {
container.innerHTML = "<p>No hay datos históricos para este mes.</p>";
return;
}
let html = "<table class=\"trend-table\"><thead><tr><th>Año</th><th>Máx</th><th>Mín</th><th>Lluvia</th></tr></thead><tbody>";
Object.keys(byYear).sort((a, b) => b - a).forEach(year => {
const maxAvg = (byYear[year].max.reduce((a,b)=>a+b,0)/byYear[year].max.length).toFixed(1);
const minAvg = (byYear[year].min.reduce((a,b)=>a+b,0)/byYear[year].min.length).toFixed(1);
const rainTotal = byYear[year].rain.reduce((a,b)=>a+b,0).toFixed(1);
html += `
<tr>
<td><strong>${year}</strong></td>
<td>${maxAvg}°C</td>
<td>${minAvg}°C</td>
<td>${rainTotal} mm</td>
</tr>
`;
});
html += "</tbody></table>";
container.innerHTML = html;
}
// ====================
// Cargar mes actual según selectedMonth
// ====================
function loadCurrentMonth() {
const ahora = new Date();
const yearActual = ahora.getFullYear();
const mesActual = ahora.getMonth();
const diaActual = ahora.getDate();
// El mes que queremos consultar
const yearBusqueda = yearActual;
const monthBusqueda = selectedMonth + 1;
// 1. Primer día del mes (Siempre el 01)
const firstDay = `${yearBusqueda}-${String(monthBusqueda).padStart(2, "0")}-01`;
// 2. Calculamos el último día teórico del mes
let ultimoDiaObj = new Date(yearBusqueda, monthBusqueda, 0);
// 3. VALIDACIÓN CRUCIAL: Si el mes seleccionado es el actual,
// limitamos la búsqueda hasta HOY para evitar el Error 500 del servidor.
if (selectedMonth === mesActual && yearBusqueda === yearActual) {
ultimoDiaObj = ahora;
}
// 4. Formateo manual YYYY-MM-DD (Evita toISOString y sus desfases UTC)
const y = ultimoDiaObj.getFullYear();
const m = String(ultimoDiaObj.getMonth() + 1).padStart(2, "0");
const d = String(ultimoDiaObj.getDate()).padStart(2, "0");
const lastDay = `${y}-${m}-${d}`;
console.log(`Petición: ${firstDay} hasta ${lastDay}`);
loadStats({ desde: firstDay, hasta: lastDay });
}
// ====================
// Inicialización
// ====================
document.addEventListener("DOMContentLoaded", () => {
updateMonthHeader();
getMoonPhase();
loadCurrentMonth();
$("prev-month").addEventListener("click", () => {
selectedMonth = (selectedMonth + 11) % 12;
updateMonthHeader();
loadCurrentMonth();
});
$("next-month").addEventListener("click", () => {
selectedMonth = (selectedMonth + 1) % 12;
updateMonthHeader();
loadCurrentMonth();
});
$("year").textContent = new Date().getFullYear();
// ====================
// Selector de ciudad
// ====================
$("city-select").addEventListener("change", (e) => {
ciudadActual = e.target.value;
loadCurrentMonth();
});
});

61
f1.html Normal file
View File

@ -0,0 +1,61 @@
<!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">Pilotos</h3>
<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>
</section>
<section class="stat-card">
<h3 id="session-info">Equipos</h3>
<table id="equipos-table">
<thead>
<tr>
<th>#</th>
<th>Nombre</th>
<th>País</th>
<th>Fundación</th>
</tr>
</thead>
<tbody>
<!-- Aquí se llenarán los equipos -->
</tbody>
</table>
</section>
</main>
<script src="js/f1.js"></script>
</body>
</html>

146
formacion.html Normal file
View File

@ -0,0 +1,146 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tatiana Villa</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<meta name="description" content="Curriculum Vitae de Tatiana Villa, desarrolladora y diseñadora web.">
<meta name="keywords" content="Tatiana Villa, curriculum, desarrolladora web, diseñadora web, tecnología, DAM">
<meta name="author" content="Tatiana Villa">
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="codigo.js"></script>
</head>
<body class="bg-black text-light">
<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>
<main class="container main-content py-5">
<div class="accordion mt-4 timeline" id="accordionExample">
<div class="card-header" id="headingOne">
<h5 class="mb-0">
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
&lt;programación&gt;
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="card-body">
<ul>
<li>(IFCD0034) Programación con .NET</li>
<li>(IFCT052PO) Gestión de sistemas con VmWare: Virtualización de aplicaciones</li>
<li>(FPGS DAM) Desarrollo de Aplicaciones Multiplataforma</li>
<li>(IFCD0210) Desarrollo de aplicaciones con tecnologías web</li>
</ul>
</div>
</div>
</div>
</div>
<div class="accordion mt-4 timeline" id="accordionExample">
<div class="card-header" id="headingTwo">
<h5 class="mb-0">
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="true" aria-controls="collapseTwo">
&lt;Sistemas&gt;
</button>
</h5>
</div>
<div id="collapseTwo" class="collapse show" aria-labelledby="headingTwo" data-parent="#accordionExample">
<div class="card-body">
<ul>
<li>Administrador de Sistemas Unix (HPUX, Linux, Debian, Ubuntu, ... )</li>
<li>(IFCT0410) Administración y diseño de redes departamentales</li>
</ul>
</div>
</div>
</div>
</div>
<div class="accordion mt-4 timeline" id="accordionExample">
<div class="card-header" id="headingFour">
<h5 class="mb-0">
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseFour" aria-expanded="true" aria-controls="collapseFour">
&lt;Otros&gt;
</button>
</h5>
</div>
<div id="collapseFour" class="collapse show" aria-labelledby="headingFour" data-parent="#accordionExample">
<div class="card-body">
<ul>
<li>(ENAE0508) Organización y proyectos de instalaciones solares fotovoltaicas</li>
<li>Robótica con arduino</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<footer>
<div class="footer">
<div class="footer">
<div>Página realizada íntegramente con código: PHP, JavaScript, HTML y CSS</div>
<div id="copyright">copyright</div>
</div>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

View File

@ -45,11 +45,11 @@
<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>

155
js/f1.js Normal file
View File

@ -0,0 +1,155 @@
// ===============================
// FUNCIONES DE CONSULTA API
// ===============================
// Obtener calendario completo de la temporada actual
async function obtenerCalendario() {
try {
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;
} catch (error) {
console.error("Error al obtener calendario:", error);
return [];
}
}
// Encontrar la siguiente carrera
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);
}
// ===============================
// PILOTOS
// ===============================
async function cargarPilotos() {
try {
const response = await fetch('/f1/api/pilotos');
const pilotos = await response.json();
const tbody = document.querySelector('#pilotos-table tbody');
tbody.innerHTML = ''; // Limpiamos antes de rellenar
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>`;
}
}
// ===============================
// ESCUDERÍAS
// ===============================
async function cargarEscuderias() {
try {
const response = await fetch('/f1/api/escuderias');
const escuderias = await response.json();
const tbody = document.querySelector('#escuderias-table tbody');
tbody.innerHTML = ''; // Limpiamos tabla
escuderias.forEach(e => {
const fila = document.createElement('tr');
fila.innerHTML = `
<td>${e.nombre}</td>
<td>${e.pais}</td>
<td>${e.motor}</td>
`;
tbody.appendChild(fila);
});
} catch (error) {
console.error('Error cargando escuderías:', error);
const tbody = document.querySelector('#escuderias-table tbody');
tbody.innerHTML = `<tr><td colspan="4">No se pudieron cargar las escuderías</td></tr>`;
}
}
// ===============================
// 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;
}
// 3) Mostrar nombre de la próxima carrera
document.querySelector(".cuenta-atras h3").textContent =
`Cuenta atrás para el GP de ${proxima.raceName}`;
// 4) Iniciar cuenta atrás
iniciarCuentaAtras(proxima.fecha);
// 5) Indicar modo carrera o pronóstico
const ahora = new Date();
if (ahora >= proxima.fecha) {
document.getElementById("session-info").textContent =
"Modo carrera — datos en vivo o resultados";
} else {
document.getElementById("session-info").textContent =
`Próxima sesión de ${proxima.raceName}`;
}
// Cargar pilotos y escuderías al inicio y cada minuto
cargarPilotos();
cargarEscuderias();
setInterval(() => { cargarPilotos(); cargarEscuderias(); }, 60000);
}
// Arrancar todo al cargar la página
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);

View File

@ -6,7 +6,11 @@
</head>
<body>
<header>
<<<<<<< HEAD
<link rel="icon" href="tatianalogo.png" type="image/x-icon">
=======
<link rel="icon" href="favicon.ico" type="image/x-icon">
>>>>>>> 1409b91efed570aae51e1eaf845151685bb4f177
<link rel="stylesheet" href="css/estilos.css">
<h1>Temario TAI AGE</h1>

47
pilotos.html Normal file
View File

@ -0,0 +1,47 @@
<!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>
</body>
</html>

View File

@ -18,10 +18,10 @@
<!-- 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
<span class="text-primary">{</span>Aplicaciones de Vanguardia <span class="text-primary">}</span>
</a>
<!-- Botón móvil -->
<!-- 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>
@ -37,23 +37,20 @@
<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>
@ -63,7 +60,7 @@
<section id="proyectos" class="py-5">
<div class="container py-5">
<h2 class="section-title mb-5">Proyectos</h2>
<h2 class="section-title mb-5">Proyectos en desarrollo</h2>
<div class="row g-4">
<div class="col-md-6 col-lg-4">
@ -124,6 +121,18 @@
</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>