This commit is contained in:
Pablo Ferreiro 2024-10-17 17:51:31 +02:00
parent 574b8f4240
commit b07af64247
11 changed files with 237 additions and 12 deletions

25
package-lock.json generated
View File

@ -10,10 +10,12 @@
"dependencies": { "dependencies": {
"@solidjs/router": "^0.14.9", "@solidjs/router": "^0.14.9",
"bulma": "^1.0.2", "bulma": "^1.0.2",
"leaflet": "^1.9.4",
"solid-icons": "^1.1.0", "solid-icons": "^1.1.0",
"solid-js": "^1.9.1" "solid-js": "^1.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/leaflet": "^1.9.12",
"sass": "^1.80.1", "sass": "^1.80.1",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"vite": "^5.4.8", "vite": "^5.4.8",
@ -1826,6 +1828,23 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/geojson": {
"version": "7946.0.14",
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz",
"integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/leaflet": {
"version": "1.9.12",
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.12.tgz",
"integrity": "sha512-BK7XS+NyRI291HIo0HCfE18Lp8oA30H1gpi1tf0mF3TgiCEzanQjOqNZ4x126SXzzi2oNSZhZ5axJp1k0iM6jg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/geojson": "*"
}
},
"node_modules/@types/resolve": { "node_modules/@types/resolve": {
"version": "1.20.2", "version": "1.20.2",
"dev": true, "dev": true,
@ -3250,6 +3269,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/leaflet": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
"license": "BSD-2-Clause"
},
"node_modules/leven": { "node_modules/leven": {
"version": "3.1.0", "version": "3.1.0",
"dev": true, "dev": true,

View File

@ -11,10 +11,12 @@
"dependencies": { "dependencies": {
"@solidjs/router": "^0.14.9", "@solidjs/router": "^0.14.9",
"bulma": "^1.0.2", "bulma": "^1.0.2",
"leaflet": "^1.9.4",
"solid-icons": "^1.1.0", "solid-icons": "^1.1.0",
"solid-js": "^1.9.1" "solid-js": "^1.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/leaflet": "^1.9.12",
"sass": "^1.80.1", "sass": "^1.80.1",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"vite": "^5.4.8", "vite": "^5.4.8",

6
src/constants/Photos.ts Normal file
View File

@ -0,0 +1,6 @@
/** Lista de fotos (Licencia CC) */
const PHOTOS: string[] = [
"https://images.pexels.com/photos/2532003/pexels-photo-2532003.jpeg?cs=srgb&dl=pexels-jamie-patterson-1318696-2532003.jpg&fm=jpg"
];
export default PHOTOS;

View File

@ -1,6 +0,0 @@
/** Lista de videos (CC) */
const VIDEOS: string[] = [
"https://www.pexels.com/es-es/download/video/13831212/?fps=60.0&h=720&w=1280"
];
export default VIDEOS;

0
src/helpers/Api.ts Normal file
View File

View File

@ -1,15 +1,15 @@
import VIDEOS from "../constants/Videos"; import PHOTOS from "../constants/Photos";
/** /**
* Clase helper para gestionar los vídeos de fondo * Clase helper para gestionar los vídeos de fondo
* encontrados en views/Home * encontrados en views/Home
*/ */
export default class Video { export default class Photo {
/** /**
* Elige un vídeo aleatoriamente de la lista * Elige un vídeo aleatoriamente de la lista
* @returns Vídeo aleatorio * @returns Vídeo aleatorio
*/ */
static random(): string { static random(): string {
return VIDEOS[Math.floor(Math.random()*VIDEOS.length)]; return PHOTOS[Math.floor(Math.random()*PHOTOS.length)];
} }
} }

View File

@ -1,6 +1,7 @@
/* @refresh reload */ /* @refresh reload */
import { render } from 'solid-js/web'; import { render } from 'solid-js/web';
import { Router } from "@solidjs/router"; import { Router } from "@solidjs/router";
import 'leaflet/dist/leaflet.css';
import './styles/bulma.scss'; import './styles/bulma.scss';
import routes from './routes'; import routes from './routes';

27
src/interfaces/Embalse.ts Normal file
View File

@ -0,0 +1,27 @@
export default interface Embalse {
// EMBALSES
ID: number;
AMBITO_NOMBRE: string;
EMBALSE_NOMBRE: string;
AGUA_TOTAL: number;
ELECTRICO_FLAG: boolean;
// LISTADO_EMBALSES
CODIGO: number;
NOMBRE: string;
EMBALSE: string;
X: string;
Y: string;
DEMARC: string;
CAUCE: string;
GOOGLE: string;
OPENSTREETMAP: string;
WIKIDATA: string;
PROVINCIA: string;
CCAA: string;
TIPO: string;
TITULAR: string;
USO: string;
COTA_CORON: string;
ALT_CIMIEN: string;
INFORME: string;
}

View File

@ -1,10 +1,15 @@
import { RouteDefinition } from "@solidjs/router"; import { RouteDefinition } from "@solidjs/router";
import Home from "./views/Home"; import Home from "./views/Home";
import Finder from "./views/Finder";
const routes: RouteDefinition[] = [ const routes: RouteDefinition[] = [
{ {
path: '/', path: '/',
component: Home component: Home
},
{
path: '/finder',
component: Finder
} }
]; ];

155
src/views/Finder.tsx Normal file
View File

@ -0,0 +1,155 @@
import { createSignal, onCleanup, onMount } from "solid-js";
import L from 'leaflet';
import { FaSolidLocationPin } from "solid-icons/fa";
import Navbar from "../partials/Navbar";
function Finder() {
const [pos, setPos] = createSignal<[number, number]>([0, 0]);
const [geo, setGeo] = createSignal(true);
let markers: L.Marker[] = [];
let first = true;
let watchId: number = -1;
let map: L.Map;
let me = L.marker([0, 0]);
/**
* Montar Leafmap
*/
onMount(() => {
map = L.map('map');
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
if (geo()) {
listenGeolocation();
}
});
/**
* Limpiar watch de geolocalización si
* está activo
*/
onCleanup(() => {
if (watchId !== -1) {
navigator.geolocation.clearWatch(watchId);
}
});
/**
* Activar / Desactivar uso de Geolocalización
*/
const toggleGeo = () => {
if (geo()) {
navigator.geolocation.clearWatch(watchId);
watchId = -1;
} else {
listenGeolocation();
}
setGeo(!geo());
}
/**
* Activar listener de geolocalización en tiempo real
*/
const listenGeolocation = () => {
watchId = navigator.geolocation.watchPosition(
(pos) => {
setPos([pos.coords.latitude, pos.coords.longitude]);
handleLocation();
},
(err) => {
alert(err.message);
}
)
}
/**
* Escribe los puntos relevantes
* (Mi ubicación y los embalses cercanos)
*/
const handleLocation = () => {
me.setLatLng(pos());
if (first) {
map.setView(pos(), 9);
me.addTo(map);
first = false;
}
// Cleanup
if (markers.length > 0) {
markers.forEach((m) => {
map.removeLayer(m);
})
markers = [];
}
// TODO: Hacer petición y sacar markers
}
/**
* Escribe la latitud de la tupla manualmente
* @param val Latitud dada por el input
*/
const setLatitudeManual = (val: string) => {
const lat = parseFloat(val);
setPos([lat, pos()[1]]);
}
/**
* Escribe la longitud de la tupla manualmente
* @param val longitud dada por el input
*/
const setLongitudeManual = (val: string) => {
const lon = parseFloat(val);
setPos([pos()[0], lon]);
}
return (
<>
<Navbar />
<section class="section">
<div class="container">
<div class="columns is-centered is-vcentered is-multiline">
<div class="column is-narrow">
<div class="field has-addons has-addons-centered">
<div class="control">
<input class="input" on:change={(e) => setLatitudeManual(e.target.value)} type="text" disabled={geo()} placeholder="Latitud" value={pos()[0]} />
</div>
<div class="control">
<input class="input" on:change={(e) => setLongitudeManual(e.target.value)} type="text" disabled={geo()} placeholder="Longitud" value={pos()[1]} />
</div>
<div class="control">
<button disabled={geo()} on:click={() => handleLocation()} class="button is-info">
Aplicar
</button>
</div>
</div>
</div>
<div class="column is-narrow">
<button on:click={() => toggleGeo()} class="button" classList={{ 'is-success': geo(), 'is-danger': !geo() }}>
<span class="icon">
<FaSolidLocationPin />
</span>
<span>Geolocalización</span>
</button>
</div>
</div>
<div id="map" style={{
height: '70vh'
}}></div>
</div>
</section>
</>
)
}
export default Finder;

View File

@ -1,11 +1,19 @@
import { FaSolidGlassWaterDroplet } from "solid-icons/fa" import { FaSolidGlassWaterDroplet } from "solid-icons/fa"
import Navbar from "../partials/Navbar" import Navbar from "../partials/Navbar"
import { createSignal } from "solid-js"
import Photo from "../helpers/Photo"
import { A } from "@solidjs/router";
function Home() { function Home() {
const [photo, setPhoto] = createSignal(Photo.random());
return ( return (
<> <>
<Navbar /> <section class="hero is-fullheight" style={{
<section class="hero is-fullheight-with-navbar"> "background-image": `url('${photo()}')`,
"background-position": 'center center',
"background-size": 'cover',
}}>
<div class="hero-body"> <div class="hero-body">
<div class="container has-text-centered"> <div class="container has-text-centered">
<div class="columns is-centered"> <div class="columns is-centered">
@ -14,6 +22,7 @@ function Home() {
<div class="columns is-centered is-vcentered is-mobile"> <div class="columns is-centered is-vcentered is-mobile">
<div class="column is-4"> <div class="column is-4">
<figure class="image is-128x128"> <figure class="image is-128x128">
{/* TODO: Agregar icono */}
<img src="https://bulma.io/assets/images/placeholders/128x128.png" /> <img src="https://bulma.io/assets/images/placeholders/128x128.png" />
</figure> </figure>
</div> </div>
@ -26,6 +35,7 @@ function Home() {
<span>Malackathon</span> <span>Malackathon</span>
</span> </span>
</p> </p>
<A class="button is-primary" href="/finder">Buscar</A>
</div> </div>
</div> </div>
</div> </div>
@ -35,7 +45,7 @@ function Home() {
</div> </div>
</section> </section>
<section class="section"> <section class="section">
<video src="https://www.pexels.com/es-es/download/video/13831212/?fps=60.0&h=720&w=1280"></video> <p>TODO: Agregar tarjetitas guapas</p>
</section> </section>
</> </>
) )