Aplicacion WEB. PHP+CSS+JS

This commit is contained in:
luisgulo 2025-06-05 01:18:37 +02:00
parent 2ce0338e4a
commit ddfaaad286
23 changed files with 513 additions and 0 deletions

135
web/css/detalle.css Normal file
View File

@ -0,0 +1,135 @@
body {
text-align: center;
}
body {
font-size: 18px; /* Aumenta el tamaño del texto */
line-height: 1.6; /* Mejora la lectura */
}
p { font-size: 18px; }
h1 { font-size: 30px; }
h2 { font-size: 26px; }
h3 { font-size: 22px; }
.container {
text-align: center;
}
ul, ol {
list-style-position: inside; /* Alinea los puntos con el texto */
}
.mapa-realista {
width: 500px;
height: auto;
display: flex;
flex-direction: column;
align-items: center;
background: #efe5dc; /* Color de papel envejecido */
padding: 15px;
border-radius: 10px;
box-shadow: 4px 4px 15px rgba(0, 0, 0, 0.3);
border: 2px solid #c4a484; /* Borde como mapa antiguo */
text-align: center;
margin: auto;
}
.mapa-realista img {
width: 100%;
height: auto;
object-fit: cover;
filter: contrast(1.1) sepia(0.3); /* Simular impresión física */
}
.carousel-item img {
width: 60%;
max-height: 400px;
object-fit: contain; /* Ajusta la imagen sin perder contenido */
margin: auto;
display: block;
}
/* Asegurar que los botones de navegación sean grandes y visibles */
.carousel-control-prev,
.carousel-control-next {
width: 12%; /* Botones más grandes */
top: 20%; /* Más cerca de la imagen (cuanto menor mas cerca) */
}
.carousel-control-prev-icon,
.carousel-control-next-icon {
background-color: rgba(0, 0, 0, 0.6); /* Fondo más visible */
border-radius: 10%;
padding: 15px; /* Botón más grande */
}
.carousel-control-prev {
left: 15%; /* Acercar el botón izquierdo al centro */
}
.carousel-control-next {
right: 15%; /* Acercar el botón derecho al centro */
}
.carousel-item {
text-align: center;
}
.polaroid {
width: 400px;
height: 450px;
display: flex;
flex-direction: column;
align-items: center;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.3);
text-align: center;
margin: auto;
}
.polaroid img {
width: 100%;
height: 80%;
object-fit: cover;
border-radius: 5px;
}
.polaroid p {
margin-top: 8px;
font-size: 16px;
font-weight: bold;
color: #333;
}
.polaroid-grande {
width: 500px;
height: auto;
display: flex;
flex-direction: column;
align-items: center;
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 4px 4px 15px rgba(0, 0, 0, 0.4);
text-align: center;
margin: auto;
}
.polaroid-grande img {
width: 100%;
height: auto;
object-fit: cover;
border-radius: 5px;
}
.polaroid-grande p {
margin-top: 10px;
font-size: 18px;
font-weight: bold;
color: #333;
}

34
web/css/index.css Normal file
View File

@ -0,0 +1,34 @@
.row {
row-gap: 30px; /* Espacio entre filas */
}
.col-md-4 {
margin-bottom: 20px; /* Espacio extra para dispositivos pequeños */
}
.polaroid {
width: 250px; /* Tamaño ajustado */
height: 350px; /* y valor aprox para mantener proporción */
display: flex;
flex-direction: column;
align-items: center;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.3);
text-align: center;
}
.polaroid img {
width: 100%;
height: 80%;
object-fit: cover; /* Ajustar imagen para no dejar contenido sin visualizar */
border-radius: 5px;
}
.polaroid p {
margin-top: 8px;
font-size: 14px;
font-weight: bold;
color: #333;
}

View File

@ -0,0 +1 @@
El Coliseo tenía capacidad para <code>50.000 espectadores</code>

View File

@ -0,0 +1,11 @@
{
"Destino": "Roma",
"Fecha_Visita": "2014-03-10",
"Foto_Principal": "roma_polaroid.jpg",
"Mapa": "roma_mapa.png",
"Fotos": ["roma_1.jpg", "roma_2.jpg", "roma_3.png"],
"Descripcion_Fotos": ["Fontana di Trevi", "Coliseo desde afuera", "Vista Coliseo y alrededores"],
"Alojamiento": "Hotel céntrico",
"Comida": ["Pasta en Trastevere", "Gelato en Piazza Navona", "Pizza en Testaccio"],
"Zonas_Visitadas": ["Coliseo", "Fontana di Trevi"]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

View File

@ -0,0 +1 @@
El <b>Cruce de Shibuya</b> es el más transitado del mundo.

View File

@ -0,0 +1,11 @@
{
"Destino": "Tokio",
"Fecha_Visita": "2025-05-12",
"Foto_Principal": "tokio_polaroid.jpg",
"Mapa": "tokio_mapa.png",
"Fotos": ["tokio_1.png", "tokio_2.png", "tokio_3.png"],
"Descripcion_Fotos": ["El Cruce de Shibuya", "Templo Sensoji", "La Torre de Tokio"],
"Alojamiento": "Hotel Shinjuku",
"Comida": ["Ramen en Ichiran", "Sushi en Tsukiji", "Okonomiyaki en Harajuku"],
"Zonas_Visitadas": ["Templo Sensoji", "Torre de Tokio"]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

144
web/detalle.php Normal file
View File

@ -0,0 +1,144 @@
<?php
// traduccion de los meses
$meses = [
"January" => "Enero", "February" => "Febrero", "March" => "Marzo",
"April" => "Abril", "May" => "Mayo", "June" => "Junio",
"July" => "Julio", "August" => "Agosto", "September" => "Septiembre",
"October" => "Octubre", "November" => "Noviembre", "December" => "Diciembre"
];
// Obtener el destino desde la URL
$destino_nombre = $_GET["destino"] ?? null;
if (!$destino_nombre) {
echo "<p>Destino no indicado.</p>";
exit;
}
// Ruta al JSON dentro del directorio del destino
$json_path = "destinos/" . $destino_nombre . "/" . "destino.json";
if (!file_exists($json_path)) {
echo "<p>Destino no encontrado.</p>";
exit;
}
// Leer el JSON del destino
$json = file_get_contents($json_path);
$destino_seleccionado = json_decode($json, true);
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title><?= $destino_seleccionado["Destino"]; ?></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/detalle.css" />
</head>
<body class="container mt-5">
<h1 style="font-family: 'Caveat', cursive; font-size: 48px;"><?= $destino_seleccionado["Destino"]; ?></h1>
<?php
$fecha = date("d F Y", strtotime($destino_seleccionado['Fecha_Visita']));
foreach ($meses as $ingles => $espanol) {
$fecha = str_replace($ingles, $espanol, $fecha);
}
echo "<p class='text-muted'>📅 Visitado el $fecha</p>";
?>
<p>
<a href="index.php" class="btn btn-secondary">🔙 Volver a la página principal</a>
<br>
</p>
<div class="polaroid-grande">
<img src="destinos/<?= $destino_nombre; ?>/<?= $destino_seleccionado['Foto_Principal']; ?>" alt="Foto de <?= $destino_seleccionado['Destino']; ?>">
<p><?= $destino_seleccionado["Destino"]; ?></p>
</div>
<br>
<h2>🗺️ Mapa del destino</h2>
<div class="mapa-realista">
<img src="destinos/<?= $destino_nombre; ?>/<?= $destino_seleccionado['Mapa']; ?>" alt="Mapa de <?= $destino_seleccionado['Destino']; ?>">
<p>Mapa de <?= $destino_seleccionado["Destino"]; ?></p>
</div>
<br>
<h2>📷 Galería de imágenes</h2>
<div id="carouselExample" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<?php foreach ($destino_seleccionado["Fotos"] as $index => $foto): ?>
<div class="carousel-item <?= $index === 0 ? 'active' : ''; ?>">
<div class="polaroid">
<img src="destinos/<?= $destino_nombre; ?>/<?= $foto; ?>" class="d-block w-100" alt="<?= $destino_seleccionado["Descripcion_Fotos"][$index]; ?>">
<p><?= $destino_seleccionado["Descripcion_Fotos"][$index]; ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExample" data-bs-slide="prev">
<span class="carousel-control-prev-icon"></span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExample" data-bs-slide="next">
<span class="carousel-control-next-icon"></span>
</button>
</div>
<br>
<h2>🏨 Alojamiento</h2>
<p><?= $destino_seleccionado["Alojamiento"]; ?></p>
<br>
<h2>🍽️ Comida</h2>
<ul style="list-style-position: inside;">
<?php foreach ($destino_seleccionado["Comida"] as $platillo): ?>
<li><?= $platillo; ?></li>
<?php endforeach; ?>
</ul>
<br>
<h2>📍 Zonas visitadas</h2>
<ul style="list-style-position: inside;">
<?php foreach ($destino_seleccionado["Zonas_Visitadas"] as $zona): ?>
<li><?= $zona; ?></li>
<?php endforeach; ?>
</ul>
<br>
<h2>🤔 Curiosidades y Anécdotas</h2>
<p>
<?php
$curiosidades_path = "destinos/" . $destino_nombre . "/curiosidades.txt";
if (file_exists($curiosidades_path)) {
$curiosidades = file($curiosidades_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($curiosidades as $curiosidad) {
echo "$curiosidad<br>";
}
} else {
echo "No hay curiosidades ni anecdotas.";
}
?>
</p>
<br>
<div class="text-center mt-4">
<a href="index.php" class="btn btn-secondary">🔙 Volver a la página principal</a>
</div>
<br><br>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

BIN
web/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

83
web/index.php Normal file
View File

@ -0,0 +1,83 @@
<?php
// Configurar el idioma español
setlocale(LC_TIME, 'es_ES.UTF-8');
// Traducir meses
$meses = [
"January" => "Enero", "February" => "Febrero", "March" => "Marzo",
"April" => "Abril", "May" => "Mayo", "June" => "Junio",
"July" => "Julio", "August" => "Agosto", "September" => "Septiembre",
"October" => "Octubre", "November" => "Noviembre", "December" => "Diciembre"
];
$destinos_dir = "destinos/";
$destinos = array_diff(scandir($destinos_dir), array('.', '..'));
// Invertir... Los ultimos serán los primeros
$destinos = array_reverse($destinos);
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Blog Personal de Viajes</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/index.css" />
<!-- Estilos de Leaflet -->
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<!-- Script de Leaflet --> <!-- <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script> -->
<!-- Funciona sin problema en local -->
<script src="js/leaflet.js"></script>
</head>
<body class="container mt-5">
<h1 class="text-center">🌍 Blog Personal de Viajes</h1>
<p class="text-center">Recordando nuestras aventuras por el mundo</p>
<!-- Contenedor del mapa -->
<div id="mapa" style="width: 85%; height: 500px;"></div>
<script src="js/mapa.js"></script>
<br>
<div class="row">
<?php foreach ($destinos as $carpeta): ?>
<?php
$json_path = $destinos_dir . $carpeta . "/" . $carpeta . ".json";
$json_path = $destinos_dir . $carpeta . "/" . "destino.json";
if (!file_exists($json_path)) continue;
$json = file_get_contents($json_path);
$destino = json_decode($json, true);
?>
<div class="col-md-4 mb-4 text-center">
<div class="polaroid">
<img src="<?= $destinos_dir . $carpeta . "/" . $destino['Foto_Principal']; ?>" alt="Foto de <?= $destino['Destino']; ?>">
<p style="font-family: 'Caveat', cursive; font-size: 32px;"><?= $destino['Destino']; ?></p>
<?php
$fecha = date("d F Y", strtotime($destino['Fecha_Visita']));
foreach ($meses as $ingles => $espanol) {
$fecha = str_replace($ingles, $espanol, $fecha);
}
echo "<p class='text-muted'>📅 Visitado el $fecha</p>";
?>
</div>
<a href="detalle.php?destino=<?= $carpeta; ?>" class="btn btn-primary mt-2">Ver más</a>
</div>
<?php endforeach; ?>
</div>
<footer class="text-center mt-5">
<p>&copy; 2025 Blog Personal de Viajes | Creado por Luis GuLo 🚀</p>
</footer>
</body>
</html>

6
web/js/leaflet.js Normal file

File diff suppressed because one or more lines are too long

19
web/js/mapa.js Normal file
View File

@ -0,0 +1,19 @@
// Inicializamos el mapa en una posición central (Ej: Madrid)
var mapa = L.map("mapa").setView([40.4168, -3.7038], 3);
// Cargar OpenStreetMap como fondo del mapa
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "&copy; OpenStreetMap contributors"
}).addTo(mapa);
// Pintar chincheta de los destinos que me devuelve mapa.php
fetch("/mapa.php")
.then(response => response.json())
.then(destinos => {
destinos.forEach(destino => {
L.marker([destino.lat, destino.lng])
.addTo(mapa)
.bindPopup(`<b>${destino.nombre}</b>`);
});
});

68
web/mapa.php Normal file
View File

@ -0,0 +1,68 @@
<?php
header("Content-Type: application/json");
$destinos_dir = "destinos"; // Carpeta principal
$destinos_array = [];
// OpenStreetMap solo permite uso con UserAgent. Indicamos que somos linuxeros...
function obtenerCoordenadas($nombre_destino) {
$url = "https://nominatim.openstreetmap.org/search?format=json&q=" . urlencode($nombre_destino);
// Iniciar sesión cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0");
// Ejecutar y obtener respuesta
$datos = curl_exec($ch);
curl_close($ch);
// Decodificar JSON
$resultado = json_decode($datos, true);
if (!empty($resultado)) {
return [
"latitud" => $resultado[0]["lat"],
"longitud" => $resultado[0]["lon"]
];
} else {
return null; // No se encontraron coordenadas
}
}
// Recorrer todas las carpetas dentro de "destinos"
foreach (scandir($destinos_dir) as $carpeta) {
if ($carpeta === "." || $carpeta === "..") continue;
$json_path = "$destinos_dir/$carpeta/destino.json"; // Ruta del JSON dentro de cada carpeta
if (!file_exists($json_path)) continue;
// Leer datos del JSON
$json_data = file_get_contents($json_path);
$destino_info = json_decode($json_data, true);
// Obtener coordenadas si no existen
if (!isset($destino_info["Latitud"], $destino_info["Longitud"])) {
$coordenadas = obtenerCoordenadas($destino_info["Destino"]);
if ($coordenadas) {
$destino_info["Latitud"] = $coordenadas["latitud"];
$destino_info["Longitud"] = $coordenadas["longitud"];
}
}
// Agregar destino al array final
if (isset($destino_info["Latitud"], $destino_info["Longitud"])) {
$destinos_array[] = [
"nombre" => $destino_info["Destino"],
"lat" => $destino_info["Latitud"],
"lng" => $destino_info["Longitud"]
];
}
}
// Convertir datos a JSON y enviarlos al frontend
echo json_encode($destinos_array);
?>