adds profile page

This commit is contained in:
Christian Beutel
2024-11-03 15:13:25 +01:00
parent 0d8ff5c83b
commit bab22301af
31 changed files with 882 additions and 133 deletions

View File

@@ -0,0 +1,163 @@
<script lang="ts">
import type { SummitLog } from "$lib/models/summit_log";
import { createEventDispatcher } from "svelte";
import { isSameDay, isToday } from "../../util/date_util";
export let logs: SummitLog[] = [];
export let colorMap: Record<string, string> = {};
const dispatch = createEventDispatcher<{
forward: {
start: Date;
end: Date;
};
backward: {
start: Date;
end: Date;
};
}>();
const weekdays = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
const months = [
"Januar",
"Februar",
"März",
"April",
"Mai",
"Juni",
"Juli",
"August",
"September",
"Oktober",
"November",
"Dezember",
];
const today = new Date();
let currentMonth = today.getMonth();
let currentYear = today.getFullYear();
let currentMonthArray: ({
date: Date | undefined;
today: boolean;
log?: SummitLog;
} | null)[];
$: currentMonthArray = generateMonthArray(currentYear, currentMonth, logs);
function calculateFirstDayOfMonthDayOfWeek(year: number, month: number) {
const date = new Date(year, month, 1);
const day = date.getDay();
return day == 0 ? 6 : day - 1;
}
function daysInMonth(year: number, month: number) {
const days = new Date(year, month + 1, 0).getDate();
return days;
}
function generateMonthArray(
year: number,
month: number,
logs: SummitLog[],
) {
const a: ({ date: Date; today: boolean; log?: SummitLog } | null)[] =
[];
const firstDay = calculateFirstDayOfMonthDayOfWeek(year, month);
const totalDays = daysInMonth(year, month);
for (let i = 0; i < 42; i++) {
if (i < firstDay || i - firstDay >= totalDays) {
a.push(null);
} else {
const date = new Date(
currentYear,
currentMonth,
i + 1 - firstDay,
);
const today = isToday(date);
const logAtDate = logs.find((l) =>
isSameDay(date, new Date(l.date)),
);
a.push({ date: date, today: today, log: logAtDate });
}
}
return a;
}
function monthPlus() {
if (currentMonth == 11) {
currentYear++;
currentMonth = 0;
} else {
currentMonth++;
}
dispatch("forward", {
start: new Date(currentYear, currentMonth, 1),
end: new Date(currentYear, currentMonth + 1, 0),
});
}
function monthMinus() {
if (currentMonth == 0) {
currentYear--;
currentMonth = 11;
} else {
currentMonth--;
}
dispatch("backward", {
start: new Date(currentYear, currentMonth, 1),
end: new Date(currentYear, currentMonth + 1, 0),
});
}
</script>
<div class="calendar-header w-full flex items-center justify-between mb-6">
<div class="calendar-month-year basis-full">
<span class="text-lg">{months[currentMonth]}</span>
<span>{currentYear}</span>
</div>
<button class="btn-icon mr-2" on:click={monthMinus}
><i class="fa fa-caret-left"></i></button
>
<button class="btn-icon" on:click={monthPlus}
><i class="fa fa-caret-right"></i></button
>
</div>
<div class="calendar-body">
<div class="grid grid-cols-7">
{#each weekdays as weekday, i}
<div
class="calendar-weekday flex items-center justify-center h-10 text-gray-500"
>
{weekday}
</div>
{/each}
</div>
<div class="grid grid-cols-7 grid-rows-6" style="aspect-ratio: 1.17/1">
{#each { length: 42 } as _, i}
<div
class="calendar-day flex items-center justify-center rounded-xl cursor-pointer"
class:today={currentMonthArray[i]?.today}
style="background-color: {colorMap[
currentMonthArray[
i
]?.log?.expand.trails_via_summit_logs?.at(0)?.expand
?.category?.name ?? ''
] ?? ''}"
>
{currentMonthArray[i]?.date?.getDate() ?? ""}
</div>
{/each}
</div>
</div>
<style>
.calendar-weekday {
font-weight: 600;
}
.calendar-month-year span {
font-weight: 600;
}
.calendar-day.today {
@apply border border-input-border;
}
</style>

View File

@@ -18,6 +18,7 @@
];
const dropdownItems = [
{ text: $_("profile"), value: "profile", icon: "user" },
{ text: $_("settings"), value: "settings", icon: "cog" },
{ text: $_("logout"), value: "logout", icon: "right-from-bracket" },
];
@@ -76,7 +77,9 @@
});
function handleDropdownClick(item: { text: string; value: any }) {
if (item.value == "logout") {
if (item.value == "profile") {
goto("/profile");
} else if (item.value == "logout") {
logout();
window.location.href = "/";
} else if (item.value == "settings") {

View File

@@ -28,12 +28,6 @@
{ text: $_("delete"), value: "delete" },
];
let totals: {
distance: number;
elevationGain: number;
duration: number;
} | null = null;
onMount(async () => {
if (!map) {
await initMap();
@@ -65,13 +59,6 @@
return;
}
const gpxObject = await GPX.parse(log.expand.gpx_data);
if (gpxObject instanceof Error) {
throw gpxObject;
}
totals = gpxObject.getTotals();
const geoJson = gpx(
new DOMParser().parseFromString(log.expand.gpx_data, "text/xml"),
);
@@ -79,7 +66,7 @@
filter: (feature: any, layer: any) => {
return feature.geometry.type !== "Point";
},
}).addTo(map)
}).addTo(map);
map.fitBounds(layer.getBounds());
map.invalidateSize();
}
@@ -88,7 +75,6 @@
if (layer) {
map?.removeLayer(layer);
}
totals = null;
}
</script>
@@ -117,25 +103,28 @@
<Dropdown items={dropdownItems} on:change></Dropdown>
{/if}
</div>
{#if totals}
{#if log.distance || log.elevation_gain || log.elevation_loss || log.duration}
<div
class="flex mt-1 gap-x-4 text-sm text-gray-500 flex-wrap mb-2"
>
<span
><i class="fa fa-left-right mr-2"></i>{formatDistance(
totals.distance,
)}</span
>
<span
><i class="fa fa-up-down mr-2"></i>{formatElevation(
totals.elevationGain,
log.distance,
)}</span
>
<span
><i class="fa fa-clock mr-2"></i>{formatTimeHHMM(
totals.duration / 1000 / 60,
log.duration,
)}</span
>
<span
><i class="fa fa-arrow-trend-up mr-2"
></i>{formatElevation(log.elevation_gain)}</span
>
<span
><i class="fa fa-arrow-trend-down mr-2"
></i>{formatElevation(log.elevation_loss)}</span
>
</div>
{/if}
<span class="whitespace-pre-wrap">{log.text}</span>

View File

@@ -11,6 +11,7 @@
import Modal from "../base/modal.svelte";
import Textarea from "../base/textarea.svelte";
import TrailPicker from "../trail/trail_picker.svelte";
import GPX from "$lib/models/gpx/gpx";
export let openModal: (() => void) | undefined = undefined;
export let closeModal: (() => void) | undefined = undefined;
@@ -26,7 +27,7 @@
initialValues: $summitLog,
validationSchema: summitLogSchema,
onSubmit: async (submittedValues) => {
if(!$form.expand.gpx_data) {
if (!$form.expand.gpx_data) {
$form.gpx = "";
}
dispatch("save", submittedValues);
@@ -38,6 +39,27 @@
$: if ($summitLog._gpx) {
$form._gpx = $summitLog._gpx;
}
async function handleTrailSelection(trailData: string | null) {
if (!trailData) {
$form.duration = undefined;
$form.elevation_gain = undefined;
$form.elevation_loss = undefined;
$form.distance = undefined;
return;
}
const gpxObject = await GPX.parse(trailData);
if (gpxObject instanceof Error) {
throw gpxObject;
}
const totals = gpxObject.getTotals();
$form.duration = totals.duration / 1000 / 60;
$form.elevation_gain = totals.elevationGain;
$form.elevation_loss = totals.elevationLoss;
$form.distance = totals.distance;
}
</script>
<Modal
@@ -68,6 +90,7 @@
bind:trailFile={$form._gpx}
bind:trailData={$form.expand.gpx_data}
label={$_("trail", { values: { n: 1 } })}
on:change={(e) => handleTrailSelection(e.detail)}
></TrailPicker>
<div class="basis-full">
<Textarea

View File

@@ -8,28 +8,30 @@
import type { Map } from "leaflet";
import { gpx } from "$lib/vendor/toGeoJSON/toGeoJSON";
import { endIcon, startIcon } from "$lib/util/leaflet_util";
import { _ } from "svelte-i18n";
import MapWithElevation from "../trail/map_with_elevation.svelte";
import type { Trail } from "$lib/models/trail";
import { gpx2trail } from "$lib/util/gpx_util";
export let summitLogs: SummitLog[];
export let showCategory: boolean = false;
let openModal: () => void;
let closeModal: () => void;
let map: Map;
let L: any;
let layerGroup: any;
let trail: Trail | null = null;
onMount(async () => {
L = (await import("leaflet")).default;
map = L.map("summit-log-table-map");
map.attributionControl.setPrefix(false);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors",
}).addTo(map);
layerGroup = L.layerGroup();
layerGroup.addTo(map);
// L = (await import("leaflet")).default;
// map = L.map("summit-log-table-map");
// map.attributionControl.setPrefix(false);
// L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
// attribution: "© OpenStreetMap contributors",
// }).addTo(map);
// layerGroup = L.layerGroup();
// layerGroup.addTo(map);
});
async function openMap(log: SummitLog) {
@@ -37,61 +39,14 @@
return;
}
layerGroup.clearLayers();
const geoJson = gpx(
new DOMParser().parseFromString(log.expand.gpx_data, "text/xml"),
);
const layer = L.geoJson(geoJson, {
onEachFeature: (feature: any, layer: any) => {
let startCoords, endCoords;
if (geoJson.features && geoJson.features.length > 0) {
const geometry = geoJson.features[0].geometry;
if (geometry.type === "LineString") {
startCoords = geometry.coordinates[0];
endCoords =
geometry.coordinates[
geometry.coordinates.length - 1
];
} else if (geometry.type === "MultiLineString") {
startCoords = (geometry as any).coordinates[0][0];
endCoords = (geometry as any).coordinates[
geometry.coordinates.length - 1
][
(geometry as any).coordinates[
geometry.coordinates.length - 1
].length - 1
];
}
}
if (startCoords && endCoords) {
const startMarker = L.marker(
[startCoords[1], startCoords[0]],
{
icon: startIcon(),
},
);
const endMarker = L.marker([endCoords[1], endCoords[0]], {
icon: endIcon(),
});
layerGroup.addLayer(startMarker);
layerGroup.addLayer(endMarker);
}
},
filter: (feature: any, layer: any) => {
return feature.geometry.type !== "Point";
},
}).addTo(map);
layerGroup.addLayer(layer);
trail = (await gpx2trail(log.expand.gpx_data)).trail;
trail.expand.gpx_data = log.expand.gpx_data;
openModal();
await tick();
map.fitBounds(layer.getBounds());
map.invalidateSize();
return;
}
</script>
@@ -99,23 +54,41 @@
<thead>
<tr class="text-sm">
<th class="w-24"></th>
<th>Date</th>
<th>Distance</th>
<th class="whitespace-nowrap">Elevation gain</th>
<th>Duration</th>
<th>{$_("date")}</th>
<th>{$_("distance")}</th>
<th>{$_("elevation-gain")}</th>
<th>{$_("elevation-loss")}</th>
<th>{$_("duration")}</th>
{#if showCategory}
<th>
{$_("category")}
</th>
{/if}
<th></th>
</tr>
</thead>
<tbody>
{#each summitLogs as log, i}
<SummitLogTableRow index={i} {log} on:open={() => openMap(log)}
<SummitLogTableRow
index={i}
{log}
on:open={() => openMap(log)}
{showCategory}
></SummitLogTableRow>
{/each}
</tbody>
</table>
<Modal id="summit-log-table-modal" title="" bind:openModal bind:closeModal>
<div slot="content" id="summit-log-table-map" class="h-96"></div>
<Modal
id="summit-log-table-modal"
size="max-w-4xl"
title=""
bind:openModal
bind:closeModal
>
<div slot="content" id="summit-log-table-map" class="h-[32rem]">
<MapWithElevation {trail} bind:map></MapWithElevation>
</div>
</Modal>
<style>

View File

@@ -2,7 +2,6 @@
import type { SummitLog } from "$lib/models/summit_log";
import "leaflet/dist/leaflet.css";
import GPX from "$lib/models/gpx/gpx";
import {
formatDistance,
formatElevation,
@@ -11,15 +10,11 @@
import { gpx } from "$lib/vendor/toGeoJSON/toGeoJSON";
import type { Map } from "leaflet";
import { createEventDispatcher, onMount } from "svelte";
import { _ } from "svelte-i18n";
export let index: number;
export let log: SummitLog;
let totals: {
distance: number;
elevationGain: number;
duration: number;
} | null = null;
export let showCategory: boolean = false;
let map: Map;
@@ -47,13 +42,6 @@
return;
}
const gpxObject = await GPX.parse(log.expand.gpx_data);
if (gpxObject instanceof Error) {
throw gpxObject;
}
totals = gpxObject.getTotals();
const geoJson = gpx(
new DOMParser().parseFromString(log.expand.gpx_data, "text/xml"),
);
@@ -78,12 +66,12 @@
<button
type="button"
on:click={openMap}
class="h-20 aspect-square shrink-0 rounded-xl !bg-background"
class="h-20 aspect-square shrink-0 rounded-xl !bg-background hover:!bg-secondary-hover transition-colors"
class:hidden={!log.expand.gpx_data}
id="mini-map-{index}"
></button>
</td>
<td class:py-4={!log.text && !log.expand.gpx_data}
<td class:py-4={!log.expand.gpx_data}
>{new Date(log.date).toLocaleDateString(undefined, {
month: "2-digit",
day: "2-digit",
@@ -92,18 +80,30 @@
})}</td
>
<td>
{formatDistance(totals?.distance)}
{formatDistance(log.distance)}
</td>
<td>
{formatElevation(totals?.elevationGain)}
</td><td>
{formatTimeHHMM(totals ? (totals?.duration / 1000 / 60) : undefined)}
{formatElevation(log.elevation_gain)}
</td>
<td>
{formatElevation(log.elevation_loss)}
</td>
<td>
{formatTimeHHMM(log.duration)}
</td>
{#if showCategory}
<td>
{$_(
log.expand.trails_via_summit_logs?.at(0)?.expand.category
?.name ?? "-",
)}
</td>
{/if}
<td>
{#if log.text}
<button on:click={() => (showText = !showText)} class="btn-icon"
><i class="fa{showText ? '' : '-regular'} fa-message"
><i class="fa{showText ? '' : '-regular'} fa-message text-gray-500"
></i></button
>
{/if}
@@ -111,11 +111,12 @@
</tr>
{#if showText}
<tr
><td class="text-left text-sm whitespace-pre-wrap pb-4" colspan="6"
>{log.text}</td
><td
class="text-left text-sm whitespace-pre-wrap pb-4"
colspan={showCategory ? 8 : 7}>{log.text}</td
></tr
>
{/if}
<tr>
<td colspan="6"> <hr /> </td>
<td colspan={showCategory ? 8 : 7}> <hr class="border-input-border" /> </td>
</tr>

View File

@@ -36,7 +36,7 @@
autofitBounds: options.autofitBounds ?? true,
});
controlElevation.clear();
controlElevation.load(gpxData);
controlElevation.load(gpxData);
}
$: if (options) {

View File

@@ -3,7 +3,7 @@
import "leaflet/dist/leaflet.css";
import type { Map } from "leaflet";
import { onMount, tick } from "svelte";
import { createEventDispatcher, onMount, tick } from "svelte";
export let trailFile: File | null;
export let trailData: string | undefined;
export let label: string = "";
@@ -12,6 +12,8 @@
let L: any;
let layer: any;
const dispatch = createEventDispatcher();
$: if (trailData !== undefined) {
showTrailOnMap();
} else {
@@ -39,6 +41,8 @@
if (trailData) {
trailFile = null;
trailData = undefined;
dispatch("change", null)
} else {
document.getElementById("trail-input")!.click();
}
@@ -56,6 +60,8 @@
trailFile = files.item(0);
trailData = await trailFile?.text();
dispatch("change", trailData);
}
async function showTrailOnMap() {

View File

@@ -7,10 +7,12 @@
"Walking": "Laufen",
"about": "Über",
"account-delete-confirm": "Du bist dabei, dein Konto zu löschen. Alle deine Routen werden ebenfalls gelöscht. Möchtest du fortfahren?",
"activity": "",
"add-entry": "Eintrag hinzufügen",
"add-to-list": "Zu Liste hinzufügen",
"add-waypoint": "Wegpunkt hinzufügen",
"added-trail-to": "Route hinzugefügt zu",
"all-activities": "",
"alphabetical": "Alphabetisch",
"already-account": "Du hast bereits ein Konto?",
"altitude": "Höhe",
@@ -59,6 +61,7 @@
"documentation": "Dokumentation",
"draw-a-route": "Route zeichnen",
"driving": "Auto",
"duration": "",
"dutch": "Niederländisch",
"easy": "Einfach",
"edit": "Bearbeiten",
@@ -66,6 +69,7 @@
"edit-list": "Liste bearbeiten",
"edit-waypoint": "Wegpunkt bearbeiten",
"elevation-gain": "Höhenunterschied",
"elevation-loss": "",
"email": "Email",
"english": "Englisch",
"entry": "Eintrag",

View File

@@ -7,10 +7,12 @@
"Walking": "Walking",
"about": "About",
"account-delete-confirm": "You are about to delete your account. All your trails will also be deleted. Do you want to proceed?",
"activity": "{n, plural, =1 {Activity} other {Activities}}",
"add-entry": "Add Entry",
"add-to-list": "Add to list",
"add-waypoint": "Add Waypoint",
"added-trail-to": "Added trail to",
"all-activities": "All activities",
"alphabetical": "Alphabetical",
"already-account": "Already have an account?",
"altitude": "Altitude",
@@ -59,6 +61,7 @@
"documentation": "Documentation",
"draw-a-route": "Draw a route",
"driving": "Driving",
"duration": "Duration",
"dutch": "Dutch",
"easy": "Easy",
"edit": "Edit",
@@ -66,6 +69,7 @@
"edit-list": "Edit List",
"edit-waypoint": "Edit Waypoint",
"elevation-gain": "Elevation Gain",
"elevation-loss": "Elevation Loss",
"email": "Email",
"english": "English",
"entry": "Entry",

View File

@@ -7,10 +7,12 @@
"Walking": "",
"about": "Informations",
"account-delete-confirm": "Vous êtes sur le point de supprimer votre compte. Toutes vos trails seront également supprimées. Voulez-vous continuer ?",
"activity": "",
"add-entry": "Ajouter une entrée",
"add-to-list": "Ajouter à une liste",
"add-waypoint": "Ajouter un point de repère",
"added-trail-to": "Ajouter un itinéraire à",
"all-activities": "",
"alphabetical": "Alphabétique",
"already-account": "Déjà un compte ?",
"altitude": "Altitude",
@@ -59,6 +61,7 @@
"documentation": "Documentation",
"draw-a-route": "",
"driving": "",
"duration": "",
"dutch": "Néerlandais",
"easy": "Facile",
"edit": "Editer",
@@ -66,6 +69,7 @@
"edit-list": "Éditer la liste",
"edit-waypoint": "Éditer le point de repère",
"elevation-gain": "Gain d'altitude",
"elevation-loss": "",
"email": "Email",
"english": "Anglais",
"entry": "Entrée",

View File

@@ -7,10 +7,12 @@
"Walking": "",
"about": "A programról",
"account-delete-confirm": "Ön most a profilját készül törölni. Minden nyomvonala törlődik. Szeretné folytatni?",
"activity": "",
"add-entry": "Bejegyzés hozzáadása",
"add-to-list": "Hozzáadás a listához",
"add-waypoint": "Útvonalpont hozzáadása",
"added-trail-to": "Hozzáadott nyomvonal a",
"all-activities": "",
"alphabetical": "Betűrendben",
"already-account": "Már rendelkezik fiókkal?",
"altitude": "Magasság",
@@ -59,6 +61,7 @@
"documentation": "Dokumentáció",
"draw-a-route": "",
"driving": "",
"duration": "",
"dutch": "Holland",
"easy": "Könnyű",
"edit": "Szerkesztés",
@@ -66,6 +69,7 @@
"edit-list": "Lista szerkesztése",
"edit-waypoint": "Útvonalpont szerkesztése",
"elevation-gain": "Magasságnövekedés",
"elevation-loss": "",
"email": "Email",
"english": "Angol",
"entry": "Bejegyzés",

View File

@@ -7,10 +7,12 @@
"Walking": "Camminare",
"about": "Su di noi",
"account-delete-confirm": "Stai per eliminare il tuo account. Tutti i tuoi percorsi saranno cancellati. Vuoi procedere?",
"activity": "",
"add-entry": "Aggiungi voce",
"add-to-list": "Aggiungi alla lista",
"add-waypoint": "Aggiungere un waypoint",
"added-trail-to": "Percorso aggiunto a",
"all-activities": "",
"alphabetical": "Alfabetico",
"already-account": "Hai già un account?",
"altitude": "Altitudine",
@@ -59,6 +61,7 @@
"documentation": "Documentazione",
"draw-a-route": "Disegna un percorso",
"driving": "Guida",
"duration": "",
"dutch": "Olandese",
"easy": "Facile",
"edit": "Modifica",
@@ -66,6 +69,7 @@
"edit-list": "Modifica lista",
"edit-waypoint": "Modifica waypoint",
"elevation-gain": "Guadagno di quota",
"elevation-loss": "",
"email": "Email",
"english": "Inglese",
"entry": "Voce",

View File

@@ -7,10 +7,12 @@
"Walking": "",
"about": "Over",
"account-delete-confirm": "Je staat op het punt je account te verwijderen. Al je wandelroutes worden hierdoor eveneens verwijderd. Wil je doorgaan?",
"activity": "",
"add-entry": "Item toevoegen",
"add-to-list": "Toevoegen aan lijst",
"add-waypoint": "Routepunt toevoegen",
"added-trail-to": "Wandelroute toegevoegd aan",
"all-activities": "",
"alphabetical": "Alfabetisch",
"already-account": "Heb je al een account?",
"altitude": "Hoogte",
@@ -59,6 +61,7 @@
"documentation": "Documentatie",
"draw-a-route": "",
"driving": "",
"duration": "",
"dutch": "Nederlands",
"easy": "Makkelijk",
"edit": "Bewerken",
@@ -66,6 +69,7 @@
"edit-list": "Lijst aanpassen",
"edit-waypoint": "Routepunt aanpassen",
"elevation-gain": "Hoogteverschil",
"elevation-loss": "",
"email": "E-mail",
"english": "Engels",
"entry": "Item",

View File

@@ -7,10 +7,12 @@
"Walking": "",
"about": "Na temat",
"account-delete-confirm": "Usuniesz swoje konto. Wszystkie twoje ścieżki zostaną usunięte. Czy chcesz kontynuować?",
"activity": "",
"add-entry": "Dodaj Pozycję",
"add-to-list": "Dodaj do listy",
"add-waypoint": "Dodaj Punkt",
"added-trail-to": "Dodaj ścieżkę do",
"all-activities": "",
"alphabetical": "Alfabetyczne",
"already-account": "Czy masz już konto?",
"altitude": "Wysokość",
@@ -59,6 +61,7 @@
"documentation": "Dokumentacja",
"draw-a-route": "",
"driving": "",
"duration": "",
"dutch": "Niderlandzki",
"easy": "Łatwy",
"edit": "Edytuj",
@@ -66,6 +69,7 @@
"edit-list": "Edytuj Listę",
"edit-waypoint": "Edytuj Punkt",
"elevation-gain": "Wzrost Wysokości",
"elevation-loss": "",
"email": "Email",
"english": "Angielski",
"entry": "Pozycja",

View File

@@ -7,10 +7,12 @@
"Walking": "",
"about": "Sobre",
"account-delete-confirm": "Você está prestes a excluir sua conta. Todas as suas trilhas também serão excluídas. Queres prosseguir?",
"activity": "",
"add-entry": "Adicionar entrada",
"add-to-list": "Adicionar à lista",
"add-waypoint": "Adicionar ponto de vista",
"added-trail-to": "Trilha adicionada para",
"all-activities": "",
"alphabetical": "Alfabético",
"already-account": "Já tem uma conta?",
"altitude": "Altitude",
@@ -59,6 +61,7 @@
"documentation": "Documentação",
"draw-a-route": "",
"driving": "",
"duration": "",
"dutch": "Holandês",
"easy": "Fácil",
"edit": "Editar",
@@ -66,6 +69,7 @@
"edit-list": "Editar lista",
"edit-waypoint": "Editar ponto de passagem",
"elevation-gain": "Ganho de elevação",
"elevation-loss": "",
"email": "Email",
"english": "Inglês",
"entry": "Entrada",

View File

@@ -7,10 +7,12 @@
"Walking": "",
"about": "关于",
"account-delete-confirm": "您现在要删除当前账户,所有的路线都会删除无法恢复,确认继续操作吗?",
"activity": "",
"add-entry": "添加日程",
"add-to-list": "添加到列表",
"add-waypoint": "添加坐标",
"added-trail-to": "添加路线到",
"all-activities": "",
"alphabetical": "字母",
"already-account": "已注册账户?",
"altitude": "海拔",
@@ -59,6 +61,7 @@
"documentation": "文档",
"draw-a-route": "",
"driving": "",
"duration": "",
"dutch": "荷兰语",
"easy": "简单",
"edit": "编辑",
@@ -66,6 +69,7 @@
"edit-list": "编辑列表",
"edit-waypoint": "编辑坐标",
"elevation-gain": "上升海拔",
"elevation-loss": "",
"email": "电子邮箱",
"english": "英语",
"entry": "日程",

View File

@@ -74,6 +74,7 @@ export default class GPX {
getTotals() {
let totalElevationGain = 0;
let totalElevationLoss = 0;
let totalDuration = 0;
let totalDistance = 0;
@@ -99,6 +100,8 @@ export default class GPX {
const elevationDiff = elevation - previousElevation;
if (elevationDiff > 0) {
totalElevationGain += elevationDiff;
} else {
totalElevationLoss += Math.abs(elevationDiff)
}
const distance = calculateDistance(
@@ -112,7 +115,7 @@ export default class GPX {
}
}
return { distance: totalDistance, elevationGain: totalElevationGain, duration: totalDuration }
return { distance: totalDistance, elevationGain: totalElevationGain, elevationLoss: totalElevationLoss, duration: totalDuration }
}
static parse(gpxString: string): Promise<GPX | Error> {

View File

@@ -1,3 +1,4 @@
import type { Trail } from "./trail";
class SummitLog {
id?: string;
@@ -5,10 +6,15 @@ class SummitLog {
text?: string;
gpx?: string;
_gpx: File | null;
distance?: number
elevation_gain?: number
elevation_loss?: number
duration?: number
author?: string;
expand: {
gpx_data?: string;
trails_via_summit_logs?: Trail[];
}
constructor(date: string, params?: { id?: string, text?: string }) {

View File

@@ -7,4 +7,5 @@ export type User = {
password: string,
avatar?: string;
language?: string;
created?: string;
}

View File

@@ -4,6 +4,23 @@ import { ClientResponseError } from "pocketbase";
import { writable, type Writable } from "svelte/store";
export const summitLog: Writable<SummitLog> = writable(new SummitLog(new Date().toISOString().substring(0, 10)));
export const summitLogs: Writable<SummitLog[]> = writable([]);
export async function summit_logs_index(f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
const r = await f('/api/v1/summit-log?', {
method: 'GET',
})
if (!r.ok) {
throw new ClientResponseError(await r.json())
}
const fetchedSummitLogs: SummitLog[] = await r.json();
summitLogs.set(fetchedSummitLogs);
return fetchedSummitLogs;
}
export async function summit_logs_create(summitLog: SummitLog) {
summitLog.author = pb.authStore.model!.id

View File

@@ -153,8 +153,8 @@ export async function trails_show(id: string, loadGPX?: boolean, f: (url: Reques
}
response.expand.gpx_data = gpxData;
for (const log of response.expand.summit_logs) {
for (const log of response.expand.summit_logs ?? []) {
const gpxData: string = await fetchGPX(log, f);
if (!log.expand) {
@@ -165,7 +165,7 @@ export async function trails_show(id: string, loadGPX?: boolean, f: (url: Reques
}
response.expand.waypoints = response.expand.waypoints || [];
response.expand.summit_logs = response.expand.summit_logs.sort((a: SummitLog, b: SummitLog) => Date.parse(a.date) - Date.parse(b.date)) || [];
response.expand.summit_logs = response.expand.summit_logs?.sort((a: SummitLog, b: SummitLog) => Date.parse(a.date) - Date.parse(b.date)) || [];
trail.set(response);

View File

@@ -1,9 +1,7 @@
import { Settings } from "$lib/models/settings";
import type { User } from "$lib/models/user";
import { pb } from "$lib/pocketbase";
import { ClientResponseError, type AuthMethodsList } from "pocketbase";
import { writable, type Writable } from "svelte/store";
import { settings_create } from "./settings_store";
export const currentUser: Writable<User | null> = writable<User | null>()

View File

@@ -0,0 +1,28 @@
export function isToday(date: Date) {
const today = new Date();
return date.setHours(0, 0, 0, 0) == today.setHours(0, 0, 0, 0)
}
export function dateExistsInList(targetDate: Date, dateList: Date[]): boolean {
const targetYear = targetDate.getFullYear();
const targetMonth = targetDate.getMonth();
const targetDay = targetDate.getDate();
for (const date of dateList) {
const year = date.getFullYear();
const month = date.getMonth();
const day = date.getDate();
if (year === targetYear && month === targetMonth && day === targetDay) {
return true;
}
}
return false;
}
export function isSameDay(d1: Date, d2: Date) {
return d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();
}