Lint and format
Some checks failed
ci/woodpecker/push/build Pipeline failed

This commit is contained in:
Alessio Davoli 2024-03-06 00:14:26 +01:00
parent 9d0dbc520b
commit c80eb89db7
34 changed files with 560 additions and 565 deletions

View file

@ -1,40 +1,40 @@
{ {
"name": "frontend", "name": "frontend",
"version": "0.6.0", "version": "0.6.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"build": "vite build && ./add-sigint.sh", "build": "vite build && ./add-sigint.sh",
"add-sigint": "./add-sigint.sh", "add-sigint": "./add-sigint.sh",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .", "lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ." "format": "prettier --plugin-search-dir . --write ."
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-node": "^4.0.1", "@sveltejs/adapter-node": "^4.0.1",
"@sveltejs/kit": "^2.5.2", "@sveltejs/kit": "^2.5.2",
"@sveltejs/vite-plugin-svelte": "^3.0.2", "@sveltejs/vite-plugin-svelte": "^3.0.2",
"@types/leaflet": "^1.9.8", "@types/leaflet": "^1.9.8",
"@typescript-eslint/eslint-plugin": "^7.1.1", "@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1", "@typescript-eslint/parser": "^7.1.1",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1", "eslint-plugin-svelte": "^2.35.1",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.2", "prettier-plugin-svelte": "^3.2.2",
"svelte": "^4.2.12", "svelte": "^4.2.12",
"svelte-check": "^3.6.6", "svelte-check": "^3.6.6",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.1.5" "vite": "^5.1.5"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@sentry/sveltekit": "^7.105.0", "@sentry/sveltekit": "^7.105.0",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet-gpx": "^1.7.0", "leaflet-gpx": "^1.7.0",
"svelte-preprocess": "^5.1.3" "svelte-preprocess": "^5.1.3"
} }
} }

90
frontend/src/app.d.ts vendored
View file

@ -9,51 +9,50 @@ declare global {
// interface PageData {} // interface PageData {}
// interface Platform {} // interface Platform {}
interface Category { interface Category {
"id": 1, id: 1;
"name_it": "Natura", name_it: 'Natura';
"name_en": "Nature", name_en: 'Nature';
"description_it": "Giri nella natura", description_it: 'Giri nella natura';
"description_en": "Countryside routes", description_en: 'Countryside routes';
"icon": "", icon: '';
"created_at": null, created_at: null;
"updated_at": null, updated_at: null;
"deleted_at": null, deleted_at: null;
"color": string, color: string;
"cover": string, cover: string;
} }
interface Sport { interface Sport {
"id": 1, id: 1;
"name_it": "Trekking", name_it: 'Trekking';
"name_en": "Trekking", name_en: 'Trekking';
"description_it": "Percorso escursionistico", description_it: 'Percorso escursionistico';
"description_en": "Trekking route", description_en: 'Trekking route';
"icon": "", icon: '';
"created_at": "2023-10-31T18:37:30.000000Z", created_at: '2023-10-31T18:37:30.000000Z';
"updated_at": null, updated_at: null;
"deleted_at": null deleted_at: null;
} }
interface SportDetails { interface SportDetails {
id: 1, id: 1;
route_id: 1, route_id: 1;
sport_id: 1, sport_id: 1;
short_description_it: "Percorso escursionistico intermedio. Buon allenamento richiesto. Sentieri facilmente percorribili. Adatto a ogni livello di abilit\u00e0. ", short_description_it: 'Percorso escursionistico intermedio. Buon allenamento richiesto. Sentieri facilmente percorribili. Adatto a ogni livello di abilit\u00e0. ';
short_description_en: "Intermediate hiking route. Good training required. Easily accessible paths. Suitable for all skill levels.", short_description_en: 'Intermediate hiking route. Good training required. Easily accessible paths. Suitable for all skill levels.';
gpx_path: "", gpx_path: '';
distance: 16800, distance: 16800;
duration: 288, duration: 288;
elevation_gain: 439, elevation_gain: 439;
elevation_loss: null, elevation_loss: null;
altitude_max: 620, altitude_max: 620;
altitude_min: 180, altitude_min: 180;
difficulty_it: "Facile", difficulty_it: 'Facile';
difficulty_en: "Easy", difficulty_en: 'Easy';
route_type_it: "Percorso ad anello", route_type_it: 'Percorso ad anello';
route_type_en: "Ring route", route_type_en: 'Ring route';
created_at: "2023-11-02T10:57:41.000000Z", created_at: '2023-11-02T10:57:41.000000Z';
updated_at: null, updated_at: null;
deleted_at: null, deleted_at: null;
sport: Sport sport: Sport;
} }
interface Route { interface Route {
id: number; id: number;
@ -66,7 +65,7 @@ declare global {
description_it: string; description_it: string;
description_en: string; description_en: string;
route_category_id: number; route_category_id: number;
created_at: "2023-11-02T10:50:07.000000Z"; created_at: '2023-11-02T10:50:07.000000Z';
updated_at: null; updated_at: null;
deleted_at: null; deleted_at: null;
route_sport_details: Array<SportDetails>; route_sport_details: Array<SportDetails>;
@ -74,9 +73,4 @@ declare global {
} }
} }
} }
export { export { Route, Category, Sport, SportDetails };
Route,
Category,
Sport,
SportDetails
};

View file

@ -1,50 +1,48 @@
<!DOCTYPE html> <!doctype html>
<html lang="it"> <html lang="it">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
<link rel="manifest" href="manifest.json" />
<head> %sveltekit.head%
<meta charset="utf-8" /> </head>
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <style>
<meta name="viewport" content="width=device-width" /> :root {
<link rel="manifest" href="manifest.json" /> --footer-height: 108px;
--accent-color: #213c8b;
--pianello-red: #de0e1b;
--pianello-yellow: #f6ae04;
--pianello-blue: #213c8b;
--card-background-color: #f9f4f1;
}
%sveltekit.head% * {
</head> box-sizing: border-box;
<style> }
:root {
--footer-height: 108px;
--accent-color: #213c8b;
--pianello-red: #de0e1b;
--pianello-yellow: #f6ae04;
--pianello-blue: #213c8b;
--card-background-color: #f9f4f1;
}
* { html {
box-sizing: border-box; width: 100%;
} height: 100%;
}
html { body {
width: 100%; width: 100%;
height: 100%; height: 100%;
} margin: 0px;
background-color: #fff;
font-family: 'Roboto-Regular';
display: grid;
}
body { @font-face {
width: 100%; font-family: 'Roboto-Regular';
height: 100%; src: url('/fonts/roboto/Roboto-Regular.ttf') format('TrueType');
margin: 0px; }
background-color: #fff; </style>
font-family: 'Roboto-Regular';
display: grid;
}
@font-face {
font-family: 'Roboto-Regular';
src: url('/fonts/roboto/Roboto-Regular.ttf') format('TrueType');
}
</style>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html> </html>

View file

@ -1,42 +1,41 @@
:root { :root {
--footer-height: calc(68px + 20px + 20px); --footer-height: calc(68px + 20px + 20px);
--accent-color: #213c8b; --accent-color: #213c8b;
--pianello-red: #de0e1b; --pianello-red: #de0e1b;
--pianello-yellow: #f6ae04; --pianello-yellow: #f6ae04;
--pianello-blue: #213c8b; --pianello-blue: #213c8b;
--card-background-color: #f9f4f1; --card-background-color: #f9f4f1;
} }
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
html { html {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
body { body {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0px; margin: 0px;
background-color: #fff; background-color: #fff;
font-family: 'Roboto-Regular'; font-family: 'Roboto-Regular';
display: grid; display: grid;
} }
header, header,
main, main,
footer { footer {
background: white; background: white;
height: 100%; height: 100%;
width: 100%; width: 100%;
display: grid; display: grid;
place-items: center; place-items: center;
} }
@font-face { @font-face {
font-family: 'Roboto-Regular'; font-family: 'Roboto-Regular';
src: url('/fonts/roboto/Roboto-Regular.ttf') format('TrueType'); src: url('/fonts/roboto/Roboto-Regular.ttf') format('TrueType');
} }

View file

@ -1,13 +1,13 @@
.header { .header {
padding: 15px; padding: 15px;
background-color: transparent; background-color: transparent;
color: black; color: black;
margin: 0 auto; margin: 0 auto;
padding-left: 25px; padding-left: 25px;
padding-right: 25px; padding-right: 25px;
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
height: 70px; height: 70px;
} }

View file

@ -1,43 +1,41 @@
<html> <html>
<head>
<style>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
<head> body {
<style> background-image: url(/splash.webp);
* { background-size: cover;
box-sizing: border-box; display: grid;
padding: 0; place-content: center;
margin: 0; height: 100%;
} font-size: 24px;
font-family: monospace;
}
.wrapper {
display: flex;
backdrop-filter: blur(5px);
border-radius: 10px;
border: 1px solid black;
}
body { #status {
background-image: url(/splash.webp); border-right: 1px solid black;
background-size: cover; }
display: grid; p {
place-content: center; padding: 20px;
height: 100%; }
font-size: 24px; </style>
font-family: monospace; </head>
}
.wrapper {
display: flex;
backdrop-filter: blur(5px);
border-radius: 10px;
border: 1px solid black;
}
#status {
border-right: 1px solid black;
}
p {
padding: 20px;
}
</style>
</head>
<body>
<div class="wrapper">
<p id="status">Code %sveltekit.status%</p>
<p id="message">%sveltekit.error.message%</p>
</div>
</body>
<body>
<div class="wrapper">
<p id="status">Code %sveltekit.status%</p>
<p id="message">%sveltekit.error.message%</p>
</div>
</body>
</html> </html>

View file

@ -1,6 +1,6 @@
export async function handleError({ error, event, status, message }) { export async function handleError({ error, event, status, message }) {
const errorId = crypto.randomUUID(); const errorId = crypto.randomUUID();
console.error(error) console.error(error);
// console.error(event) // console.error(event)
// console.error(status) // console.error(status)
return { return {

View file

@ -9,7 +9,7 @@ export async function handleFetch({ request, fetch }) {
export async function handleError({ error, event, status, message }) { export async function handleError({ error, event, status, message }) {
const errorId = crypto.randomUUID(); const errorId = crypto.randomUUID();
console.error(error) console.error(error);
// console.error(event) // console.error(event)
// console.error(status) // console.error(status)
return { return {

View file

@ -30,7 +30,6 @@
box-shadow: 0 0 50px #ccc; box-shadow: 0 0 50px #ccc;
background-color: var(--card-background-color); background-color: var(--card-background-color);
margin: 0 auto; margin: 0 auto;
} }
#container > a { #container > a {

View file

@ -1,40 +1,40 @@
<script lang="ts"> <script lang="ts">
import '../../css/header.css'; import '../../css/header.css';
export const title: string = 'Naturalistici'; export const title: string = 'Naturalistici';
const goBack = () => { const goBack = () => {
history.back(); history.back();
}; };
</script> </script>
<div class='header'> <div class="header">
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-missing-attribute --> <!-- svelte-ignore a11y-missing-attribute -->
<a on:click={goBack}> <a on:click={goBack}>
<img class="back" src="/images/black-back-arrow.png" alt="" /> <img class="back" src="/images/black-back-arrow.png" alt="" />
</a> </a>
<img src="/images/app-bar-logo.png" alt="" /> <img src="/images/app-bar-logo.png" alt="" />
</div> </div>
<style> <style>
div { div {
background-color: transparent; background-color: transparent;
color: black; color: black;
} }
div a { div a {
cursor: pointer; cursor: pointer;
} }
div a img { div a img {
height: 40px; height: 40px;
} }
img { img {
height: 40px; height: 40px;
} }
.back { .back {
height: 20px; height: 20px;
} }
</style> </style>

View file

@ -8,7 +8,7 @@
}; };
</script> </script>
<div class='header'> <div class="header">
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-missing-attribute --> <!-- svelte-ignore a11y-missing-attribute -->

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {PUBLIC_BACKEND_URL} from '$env/static/public' import { PUBLIC_BACKEND_URL } from '$env/static/public';
export let name: string; export let name: string;
export let id: number; export let id: number;
@ -7,7 +7,7 @@
export const path = `/paths/${id}`; export const path = `/paths/${id}`;
export let src: string; export let src: string;
let image = '/archi.png' let image = '/archi.png';
switch (id) { switch (id) {
case 1: case 1:
image = '/archi.png'; image = '/archi.png';
@ -30,16 +30,16 @@
<div class="bold">{name}</div> <div class="bold">{name}</div>
</div> </div>
</div> </div>
<div class="route-card-right" style:background-image='url({PUBLIC_BACKEND_URL}{src})' /> <div class="route-card-right" style:background-image="url({PUBLIC_BACKEND_URL}{src})" />
</a> </a>
<style> <style>
a { a {
text-decoration: inherit; text-decoration: inherit;
color: inherit; color: inherit;
cursor: pointer; cursor: pointer;
display: grid; display: grid;
grid-template-columns: 20% minmax(1px,1fr) 20%; grid-template-columns: 20% minmax(1px, 1fr) 20%;
max-width: 100%; max-width: 100%;
width: calc(100% - 20px); width: calc(100% - 20px);
margin: 0 auto; margin: 0 auto;

View file

@ -1,16 +1,16 @@
<script lang="ts"> <script lang="ts">
import {PUBLIC_BACKEND_URL} from '$env/static/public' import { PUBLIC_BACKEND_URL } from '$env/static/public';
export let route: App.Route; export let route: App.Route;
</script> </script>
<a href="/routes/{route.id}"> <a href="/routes/{route.id}">
<div id="image" style:background-image="url({PUBLIC_BACKEND_URL}{route.cover})" /> <div id="image" style:background-image="url({PUBLIC_BACKEND_URL}{route.cover})" />
<div id='path-holder'> <div id="path-holder">
<p class='path-name'>{route.title_it}</p> <p class="path-name">{route.title_it}</p>
</div> </div>
<div id='duration-holder'> <div id="duration-holder">
<div style='font-size: 15px;'>Dislivello</div> <div style="font-size: 15px;">Dislivello</div>
<p id="duration">{route.elevation_gain}</p> <p id="duration">{route.elevation_gain}</p>
</div> </div>
</a> </a>

View file

@ -1,13 +1,13 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import { dev } from '$app/environment' import { dev } from '$app/environment';
let visible = dev ? false : true; let visible = dev ? false : true;
let time = 2000; let time = 2000;
onMount(() => { onMount(() => {
if(dev) return if (dev) return;
setTimeout(() => { setTimeout(() => {
visible = false; visible = false;
@ -16,9 +16,9 @@
</script> </script>
{#if visible} {#if visible}
<img class='background' transition:fade src="/splash.webp" alt="splash" /> <img class="background" transition:fade src="/splash.webp" alt="splash" />
<div class='wrapper'> <div class="wrapper">
<img transition:fade class='logo' src="/images/splash-logo.png" alt="splash-logo" /> <img transition:fade class="logo" src="/images/splash-logo.png" alt="splash-logo" />
</div> </div>
{/if} {/if}

View file

@ -12,8 +12,8 @@
let component = InfoTabTrekking; let component = InfoTabTrekking;
onMount(() => { onMount(() => {
console.log(route) console.log(route);
}) });
const dispatchClick = (c: InfoTabTrekking | InfoTabBike | DescTab | MapTab) => { const dispatchClick = (c: InfoTabTrekking | InfoTabBike | DescTab | MapTab) => {
component = c; component = c;
dispatch('tab-click', { component }); dispatch('tab-click', { component });
@ -21,14 +21,30 @@
</script> </script>
<div id="tabs"> <div id="tabs">
<button class:active={component === InfoTabTrekking} on:click={() => dispatchClick(InfoTabTrekking)} id="info-trekking"> <img src='/trekking.svg' alt='trekking'> </button> <button
<button class:active={component === InfoTabBike} on:click={() => dispatchClick(InfoTabBike)} id="info-bike"> <img src='/bike.svg' alt='bike'> </button> class:active={component === InfoTabTrekking}
<button class:active={component === DescTab} on:click={() => dispatchClick(DescTab)} id="desc"> Descrizione</button> on:click={() => dispatchClick(InfoTabTrekking)}
<button class:active={component === MapTab} on:click={() => dispatchClick(MapTab)} id="map"> Mappa</button> id="info-trekking"
>
<img src="/trekking.svg" alt="trekking" />
</button>
<button
class:active={component === InfoTabBike}
on:click={() => dispatchClick(InfoTabBike)}
id="info-bike"
>
<img src="/bike.svg" alt="bike" />
</button>
<button class:active={component === DescTab} on:click={() => dispatchClick(DescTab)} id="desc">
Descrizione</button
>
<button class:active={component === MapTab} on:click={() => dispatchClick(MapTab)} id="map">
Mappa</button
>
</div> </div>
<div id="container"> <div id="container">
<div class="tab" bind:this={ref} role="tab"> <div class="tab" bind:this={ref} role="tab">
<svelte:component this={component} route={route} /> <svelte:component this={component} {route} />
</div> </div>
</div> </div>
@ -72,7 +88,8 @@
border-bottom: 1px solid black !important; border-bottom: 1px solid black !important;
} }
#info-bike, #info-trekking { #info-bike,
#info-trekking {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;

View file

@ -1,4 +1,4 @@
<script lang='ts'> <script lang="ts">
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
export let route: App.Route; export let route: App.Route;

View file

@ -50,28 +50,28 @@
</div> </div>
<style> <style>
#grid { #grid {
display: grid; display: grid;
grid-template-rows: repeat(3, 33%); grid-template-rows: repeat(3, 33%);
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
width: 100%; width: 100%;
background: white; background: white;
place-items: center; place-items: center;
font-size: 14px; font-size: 14px;
} }
#grid div { #grid div {
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
text-align: center; text-align: center;
flex-direction: column; flex-direction: column;
} }
#grid div > p { #grid div > p {
padding: 10px; padding: 10px;
margin: 0px; margin: 0px;
} }
#grid div p:nth-child(2) { #grid div p:nth-child(2) {
font-weight: bold; font-weight: bold;
font-size: 16px; font-size: 16px;
} }
</style> </style>

View file

@ -50,28 +50,28 @@
</div> </div>
<style> <style>
#grid { #grid {
display: grid; display: grid;
grid-template-rows: repeat(3, 33%); grid-template-rows: repeat(3, 33%);
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
width: 100%; width: 100%;
background: white; background: white;
place-items: center; place-items: center;
font-size: 14px; font-size: 14px;
} }
#grid div { #grid div {
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
text-align: center; text-align: center;
flex-direction: column; flex-direction: column;
} }
#grid div > p { #grid div > p {
padding: 10px; padding: 10px;
margin: 0px; margin: 0px;
} }
#grid div p:nth-child(2) { #grid div p:nth-child(2) {
font-weight: bold; font-weight: bold;
font-size: 16px; font-size: 16px;
} }
</style> </style>

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { onMount, onDestroy } from 'svelte'; import { onMount, onDestroy } from 'svelte';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
const mapMarkerIcon = new URL('/icons/map.png', import.meta.url).href const mapMarkerIcon = new URL('/icons/map.png', import.meta.url).href;
export let route; export let route;
const pianelloCoordinates = [43.14, 12.53]; const pianelloCoordinates = [43.14, 12.53];
@ -14,54 +14,55 @@
let longitude; let longitude;
let accuracy; let accuracy;
let watchPositionId: number; let watchPositionId: number;
const errorMessage = "Geolocation not available"; const errorMessage = 'Geolocation not available';
const attribution = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'; const attribution =
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
const openStreetMapTile = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'; const openStreetMapTile = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
let errored = false; let errored = false;
const watchPosition = async () => { const watchPosition = async () => {
if (!("geolocation" in navigator)) { if (!('geolocation' in navigator)) {
errored = true; errored = true;
throw new Error(errorMessage) throw new Error(errorMessage);
} }
const options = { const options = {
enableHighAccuracy: true, enableHighAccuracy: true,
timeout: 5000, timeout: 5000,
maximumAge: 0, maximumAge: 0
}; };
function success(pos: GeolocationPosition) { function success(pos: GeolocationPosition) {
const crd = pos.coords; const crd = pos.coords;
let string = ""; let string = '';
latitude = crd.latitude; latitude = crd.latitude;
longitude = crd.longitude; longitude = crd.longitude;
accuracy = crd.accuracy; accuracy = crd.accuracy;
const icon = leaflet.icon({ const icon = leaflet.icon({
iconUrl: mapMarkerIcon, iconUrl: mapMarkerIcon,
iconSize: [75, 75], // size of the icon iconSize: [75, 75] // size of the icon
}); });
userMarker = leaflet.marker([latitude, longitude], {icon}).addTo(map); userMarker = leaflet.marker([latitude, longitude], { icon }).addTo(map);
// move the map to have the location in its center // move the map to have the location in its center
map.panTo(userMarker.getLatLng()); map.panTo(userMarker.getLatLng());
string += "Your current position is:"; string += 'Your current position is:';
string += `Latitude : ${crd.latitude}`; string += `Latitude : ${crd.latitude}`;
string += `Longitude: ${crd.longitude}`; string += `Longitude: ${crd.longitude}`;
string += `More or less ${crd.accuracy} meters.`; string += `More or less ${crd.accuracy} meters.`;
} }
function error(err) { function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`); console.warn(`ERROR(${err.code}): ${err.message}`);
} }
watchPositionId = navigator.geolocation.watchPosition(success, error, options); watchPositionId = navigator.geolocation.watchPosition(success, error, options);
}; };
const renderMap = () => { const renderMap = () => {
layerGroup = leaflet.layerGroup(); layerGroup = leaflet.layerGroup();
@ -75,22 +76,22 @@
map.setView(pianelloCoordinates, 13); map.setView(pianelloCoordinates, 13);
leaflet leaflet.tileLayer(openStreetMapTile, { attribution }).addTo(map);
.tileLayer(openStreetMapTile, {attribution}) };
.addTo(map);
}
const renderGPX = () => { const renderGPX = () => {
const gpx = "/gpx/tidone.gpx"; // URL to your GPX file or the GPX itself const gpx = '/gpx/tidone.gpx'; // URL to your GPX file or the GPX itself
new leafletGPX(gpx, {async: true}).on('loaded', function(e) { new leafletGPX(gpx, { async: true })
map.fitBounds(e.target.getBounds()); .on('loaded', function (e) {
}).addTo(map); map.fitBounds(e.target.getBounds());
} })
.addTo(map);
};
onMount(async () => { onMount(async () => {
await watchPosition(); await watchPosition();
leaflet = await import('leaflet'); leaflet = await import('leaflet');
const {GPX} = await import('leaflet-gpx'); const { GPX } = await import('leaflet-gpx');
leafletGPX = GPX; leafletGPX = GPX;
renderMap(); renderMap();
@ -115,10 +116,14 @@
{/if} {/if}
<svelte:head> <svelte:head>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" <link
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" rel="stylesheet"
crossorigin=""/> href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""
/>
</svelte:head> </svelte:head>
<style> <style>
#map { #map {
height: 100%; height: 100%;

View file

@ -1,12 +1,6 @@
let latitude; let latitude;
let longitude; let longitude;
onmessage = () => {};
onmessage = () => { export {};
};
export { };

View file

@ -1,61 +1,60 @@
import {PUBLIC_BACKEND_URL} from '$env/static/public' import { PUBLIC_BACKEND_URL } from '$env/static/public';
const API_URL = `${PUBLIC_BACKEND_URL}/api` const API_URL = `${PUBLIC_BACKEND_URL}/api`;
const getAllRoutes = async () => { const getAllRoutes = async () => {
let data = []; let data = [];
const response = await fetch(`${API_URL}/all-routes`); const response = await fetch(`${API_URL}/all-routes`);
const json = await response.json(); const json = await response.json();
data = json; data = json;
return data; return data;
} };
const getRouteCategories = async () => { const getRouteCategories = async () => {
let data = []; let data = [];
const response = await fetch(`${API_URL}/route-categories`); const response = await fetch(`${API_URL}/route-categories`);
const json = await response.json(); const json = await response.json();
data = json; data = json;
return data; return data;
} };
const getRouteByCategory = async (categoryId: number) => { const getRouteByCategory = async (categoryId: number) => {
let data = []; let data = [];
const response = await fetch(`${API_URL}/route-by-category/${categoryId}`); const response = await fetch(`${API_URL}/route-by-category/${categoryId}`);
const json = await response.json(); const json = await response.json();
data = json; data = json;
return data; return data;
} };
const getRoute = async (routeId: number) => { const getRoute = async (routeId: number) => {
let data = {}; let data = {};
const response = await fetch(`${API_URL}/route/${routeId}`); const response = await fetch(`${API_URL}/route/${routeId}`);
const json = await response.json(); const json = await response.json();
data = json; data = json;
return data;
}
return data;
};
const getSport = async (routeId: number, sportId: number) => { const getSport = async (routeId: number, sportId: number) => {
let data = {}; let data = {};
const response = await fetch(`${API_URL}/route/${routeId}/${sportId}`); const response = await fetch(`${API_URL}/route/${routeId}/${sportId}`);
const json = await response.json(); const json = await response.json();
data = json; data = json;
return data; return data;
} };
const getPlacemarks = async (routeId: number, sportId: number) => { const getPlacemarks = async (routeId: number, sportId: number) => {
let data = {}; let data = {};
const response = await fetch(`${API_URL}/getPlacemarks/${routeId}/${sportId}`); const response = await fetch(`${API_URL}/getPlacemarks/${routeId}/${sportId}`);
const json = await response.json(); const json = await response.json();
data = json; data = json;
return data; return data;
} };
export { getAllRoutes, getPlacemarks, getSport, getRoute, getRouteByCategory, getRouteCategories }; export { getAllRoutes, getPlacemarks, getSport, getRoute, getRouteByCategory, getRouteCategories };

View file

@ -2,7 +2,7 @@
import { page } from '$app/stores'; import { page } from '$app/stores';
</script> </script>
<div id='container'> <div id="container">
<div class="wrapper"> <div class="wrapper">
<p id="status">{$page.status}</p> <p id="status">{$page.status}</p>
<p id="message">{$page.error?.message}</p> <p id="message">{$page.error?.message}</p>
@ -22,9 +22,9 @@
display: grid; display: grid;
place-content: center; place-content: center;
height: 100dvh; height: 100dvh;
width: 100dvw; width: 100dvw;
z-index: 99; z-index: 99;
position: absolute; position: absolute;
font-size: 24px; font-size: 24px;
font-family: monospace; font-family: monospace;
} }

View file

@ -8,7 +8,7 @@
let node: HTMLElement; let node: HTMLElement;
onMount(() => { onMount(() => {
if(dev) return; if (dev) return;
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
addEventListener('load', function () { addEventListener('load', function () {
@ -32,8 +32,8 @@
} }
}); });
onNavigate((navigation: { complete: any; }) => { onNavigate((navigation: { complete: any }) => {
if (!(document.startViewTransition)) return; if (!document.startViewTransition) return;
return new Promise<void>((resolve) => { return new Promise<void>((resolve) => {
document?.startViewTransition(async () => { document?.startViewTransition(async () => {

View file

@ -9,7 +9,7 @@
<div id="welcome-message">Benvenuti a <span class="bold">Pianello Val Tidone</span></div> <div id="welcome-message">Benvenuti a <span class="bold">Pianello Val Tidone</span></div>
<div id="route-cards"> <div id="route-cards">
{#each categories as category} {#each categories as category}
<Path src={category.cover} color={category.color} name="{category.name_it}" id={category.id} /> <Path src={category.cover} color={category.color} name={category.name_it} id={category.id} />
{/each} {/each}
</div> </div>
</main> </main>

View file

@ -9,7 +9,7 @@ export async function load({ fetch }) {
const response = await fetch(`${API_URL}/route-categories`); const response = await fetch(`${API_URL}/route-categories`);
categories = await response.json(); categories = await response.json();
} catch (ex) { } catch (ex) {
error(404, { message: 'API Not Found'}); error(404, { message: 'API Not Found' });
} }
return { categories }; return { categories };

View file

@ -1,27 +1,26 @@
import { getRouteByCategory, getRouteCategories } from '$lib/repo.js';
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
import {PUBLIC_BACKEND_URL} from '$env/static/public'; import { PUBLIC_BACKEND_URL } from '$env/static/public';
const API_URL = `${PUBLIC_BACKEND_URL}/api`; const API_URL = `${PUBLIC_BACKEND_URL}/api`;
export async function load({ params, fetch }) { export async function load({ params, fetch }) {
const response = await fetch(`${API_URL}/route-categories`); const response = await fetch(`${API_URL}/route-categories`);
const categories: App.Category[] = await response.json(); const categories: App.Category[] = await response.json();
const categoryId = Number(params.slug); const categoryId = Number(params.slug);
const category: App.Category = categories.find(c => c.id === categoryId) as App.Category; const category: App.Category = categories.find((c) => c.id === categoryId) as App.Category;
if (!category) { if (!category) {
error(404); error(404, { message: 'Path not found' });
} }
const response2 = await fetch(`${API_URL}/route-by-category/${categoryId}`); const response2 = await fetch(`${API_URL}/route-by-category/${categoryId}`);
const routes = await response2.json(); const routes = await response2.json();
const toReturn = { const toReturn = {
category: category.name_it, category: category.name_it,
routes, routes
} };
return toReturn; return toReturn;
} }

View file

@ -8,7 +8,7 @@
let divider: HTMLDivElement; let divider: HTMLDivElement;
let isMap: boolean = false; let isMap: boolean = false;
const tabClick = (event) => { const tabClick = (event) => {
isMap = event.detail.component === MapTab; isMap = event.detail.component === MapTab;
}; };
</script> </script>
@ -18,7 +18,7 @@
<div bind:this={divider} id="divider" class:move-to-top={isMap}> <div bind:this={divider} id="divider" class:move-to-top={isMap}>
<div id="banner"> <div id="banner">
<p class='path-name'>Percorso <b>{data.name_it}</b></p> <p class="path-name">Percorso <b>{data.name_it}</b></p>
<p id="duration">Dislivello {data?.route_sport_details[0]?.elevation_gain} m</p> <p id="duration">Dislivello {data?.route_sport_details[0]?.elevation_gain} m</p>
</div> </div>
<Tabs on:tab-click={tabClick} route={data}></Tabs> <Tabs on:tab-click={tabClick} route={data}></Tabs>

View file

@ -1,16 +1,16 @@
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
import {PUBLIC_BACKEND_URL} from '$env/static/public' import { PUBLIC_BACKEND_URL } from '$env/static/public';
const API_URL = `${PUBLIC_BACKEND_URL}/api` const API_URL = `${PUBLIC_BACKEND_URL}/api`;
export async function load({ params, fetch }) { export async function load({ params, fetch }) {
const routeId = Number(params.slug); const routeId = Number(params.slug);
const response = await fetch(`${API_URL}/route/${routeId}`); const response = await fetch(`${API_URL}/route/${routeId}`);
const route = await response.json(); const route = await response.json();
if (!route) { if (!route) {
error(404); error(404, { message: 'Route non found' });
} }
return route; return route;
} }

View file

@ -9,76 +9,72 @@ import { build, files, version, prerendered } from '$service-worker';
const CACHE = `sw-cache-${version}`; const CACHE = `sw-cache-${version}`;
const ASSETS = [ const ASSETS = [
...build, // the app itself ...build, // the app itself
...files, // everything in `static`, ...files, // everything in `static`,
...prerendered // dynamic routes ...prerendered // dynamic routes
]; ];
let client; let client;
addEventListener('message', event => { addEventListener('message', (event) => {
client = event.source; client = event.source;
}); });
self.addEventListener('install', (event) => { self.addEventListener('install', (event) => {
// Create a new cache and add all files to it // Create a new cache and add all files to it
async function addFilesToCache() { async function addFilesToCache() {
const cache = await caches.open(CACHE); const cache = await caches.open(CACHE);
await cache.addAll(ASSETS); await cache.addAll(ASSETS);
} }
event.waitUntil(addFilesToCache()); event.waitUntil(addFilesToCache());
}); });
self.addEventListener('activate', (event) => { self.addEventListener('activate', (event) => {
// Remove previous cached data from disk // Remove previous cached data from disk
async function deleteOldCaches() { async function deleteOldCaches() {
for (const key of await caches.keys()) { for (const key of await caches.keys()) {
if (key !== CACHE) await caches.delete(key); if (key !== CACHE) await caches.delete(key);
} }
} }
event.waitUntil(deleteOldCaches()); event.waitUntil(deleteOldCaches());
let channel; let channel;
if(BroadcastChannel) { if (BroadcastChannel) {
channel = new BroadcastChannel('sw-messages'); channel = new BroadcastChannel('sw-messages');
channel.postMessage({title: 'Cache Downloaded'}); channel.postMessage({ title: 'Cache Downloaded' });
} else { } else {
client.postMessage("Cache Downloaded") client.postMessage('Cache Downloaded');
} }
}); });
self.addEventListener('fetch', (event) => { self.addEventListener('fetch', (event) => {
// ignore POST requests etc // ignore POST requests etc
if (event.request.method !== 'GET') return; if (event.request.method !== 'GET') return;
async function respond() { async function respond() {
const url = new URL(event.request.url); const url = new URL(event.request.url);
const cache = await caches.open(CACHE); const cache = await caches.open(CACHE);
// `build`/`files` can always be served from the cache // `build`/`files` can always be served from the cache
if (ASSETS.includes(url.pathname)) { if (ASSETS.includes(url.pathname)) {
return cache.match(url.pathname); return cache.match(url.pathname);
} }
// for everything else, try the network first, but // for everything else, try the network first, but
// fall back to the cache if we're offline // fall back to the cache if we're offline
try { try {
const response = await fetch(event.request); const response = await fetch(event.request);
if (response.status === 200) { if (response.status === 200) {
cache.put(event.request, response.clone()); cache.put(event.request, response.clone());
} }
return response; return response;
} catch { } catch {
return cache.match(event.request); return cache.match(event.request);
} }
} }
event.respondWith(respond()); event.respondWith(respond());
}); });

View file

@ -1,47 +1,46 @@
{ {
"id": "/", "id": "/",
"name": "PianelloExperience", "name": "PianelloExperience",
"short_name": "PianelloExperience", "short_name": "PianelloExperience",
"start_url": "/", "start_url": "/",
"display": "standalone", "display": "standalone",
"background_color": "#fff", "background_color": "#fff",
"description": "PianelloExperience", "description": "PianelloExperience",
"icons": [ "icons": [
{ {
"src": "images/app-icon-48x48.jpeg", "src": "images/app-icon-48x48.jpeg",
"sizes": "48x48", "sizes": "48x48",
"type": "image/jpeg" "type": "image/jpeg"
}, },
{ {
"src": "images/app-icon-72x72.jpeg", "src": "images/app-icon-72x72.jpeg",
"sizes": "72x72", "sizes": "72x72",
"type": "image/jpeg" "type": "image/jpeg"
}, },
{ {
"src": "images/app-icon-96x96.jpeg", "src": "images/app-icon-96x96.jpeg",
"sizes": "96x96", "sizes": "96x96",
"type": "image/jpeg" "type": "image/jpeg"
}, },
{ {
"src": "images/app-icon-144x144.jpeg", "src": "images/app-icon-144x144.jpeg",
"sizes": "144x144", "sizes": "144x144",
"type": "image/jpeg" "type": "image/jpeg"
}, },
{ {
"src": "images/app-icon-168x168.jpeg", "src": "images/app-icon-168x168.jpeg",
"sizes": "168x168", "sizes": "168x168",
"type": "image/jpeg" "type": "image/jpeg"
}, },
{ {
"src": "images/app-icon-192x192.png", "src": "images/app-icon-192x192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "images/app-icon-512x512.png", "src": "images/app-icon-512x512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
} }
] ]
} }

View file

@ -1,4 +1,4 @@
import adapter from "@sveltejs/adapter-node"; import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
@ -6,17 +6,17 @@ const config = {
preprocess: vitePreprocess(), preprocess: vitePreprocess(),
kit: { kit: {
files: { files: {
serviceWorker: 'src/sw.ts', serviceWorker: 'src/sw.ts'
}, },
serviceWorker: { serviceWorker: {
register: false, register: false
}, },
adapter: adapter({ adapter: adapter({
fallback: null, fallback: null,
precompress: true, precompress: true,
strict: true strict: true
}), })
}, }
}; };
export default config; export default config;

View file

@ -1,22 +1,20 @@
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from '@sveltejs/kit/vite';
import adapter from "@sveltejs/adapter-node"; import adapter from '@sveltejs/adapter-node';
const config = { const config = {
plugins: [ plugins: [sveltekit()],
sveltekit(), test: {
], include: ['src/**/*.{test,spec}.{js,ts}']
test: { },
include: ["src/**/*.{test,spec}.{js,ts}"], build: {
}, minify: 'esbuild',
build: { target: 'esnext'
minify: "esbuild", },
target: "esnext", kit: {
}, adapter: adapter({
kit: { precompress: false
adapter: adapter({ })
precompress: false, }
})
},
}; };
export default config; export default config;