Aplicacion WEB. PHP+CSS+JS
135
web/css/detalle.css
Normal 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
@ -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;
|
||||
}
|
1
web/destinos/roma/curiosidades.txt
Normal file
@ -0,0 +1 @@
|
||||
El Coliseo tenía capacidad para <code>50.000 espectadores</code>
|
11
web/destinos/roma/destino.json
Normal 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"]
|
||||
}
|
BIN
web/destinos/roma/roma_1.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
web/destinos/roma/roma_2.jpg
Normal file
After Width: | Height: | Size: 170 KiB |
BIN
web/destinos/roma/roma_3.png
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
web/destinos/roma/roma_mapa.png
Normal file
After Width: | Height: | Size: 328 KiB |
BIN
web/destinos/roma/roma_polaroid.jpg
Normal file
After Width: | Height: | Size: 95 KiB |
1
web/destinos/tokio/curiosidades.txt
Normal file
@ -0,0 +1 @@
|
||||
El <b>Cruce de Shibuya</b> es el más transitado del mundo.
|
11
web/destinos/tokio/destino.json
Normal 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"]
|
||||
}
|
BIN
web/destinos/tokio/tokio_1.png
Normal file
After Width: | Height: | Size: 247 KiB |
BIN
web/destinos/tokio/tokio_2.png
Normal file
After Width: | Height: | Size: 191 KiB |
BIN
web/destinos/tokio/tokio_3.png
Normal file
After Width: | Height: | Size: 226 KiB |
BIN
web/destinos/tokio/tokio_mapa.png
Normal file
After Width: | Height: | Size: 284 KiB |
BIN
web/destinos/tokio/tokio_mapa2.png
Normal file
After Width: | Height: | Size: 150 KiB |
BIN
web/destinos/tokio/tokio_polaroid.jpg
Normal file
After Width: | Height: | Size: 146 KiB |
144
web/detalle.php
Normal 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
After Width: | Height: | Size: 42 KiB |
83
web/index.php
Normal 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>© 2025 Blog Personal de Viajes | Creado por Luis GuLo 🚀</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
6
web/js/leaflet.js
Normal file
19
web/js/mapa.js
Normal 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: "© 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
@ -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);
|
||||
?>
|