finishes trail create

This commit is contained in:
Christian Beutel
2024-01-29 21:30:54 +01:00
parent 2d4c673060
commit efaf0d4e5c
47 changed files with 1739 additions and 130 deletions

View File

@@ -0,0 +1,31 @@
<script lang="ts">
export let type: "button" | "submit" | "reset" | null | undefined =
undefined;
export let icon: string = "";
export let extraClasses: string = "";
export let primary: boolean = false;
export let secondary: boolean = false;
export let large: boolean = false;
export let loading: boolean = false;
export let disabled: boolean = false;
</script>
<button
class={extraClasses}
class:btn-primary={primary}
class:btn-secondary={secondary}
class:btn-large={large}
class:btn-disabled={disabled || loading}
disabled={disabled || loading}
on:click
{type}
>
{#if !loading}
{#if icon}
<i class="fa fa-{icon} mr-2"></i>
{/if}
<slot />
{:else}
<div class="spinner"></div>
{/if}
</button>

View File

@@ -0,0 +1,29 @@
<script lang="ts">
export let name: string = "";
export let value: string | number | Date = "";
export let label: string = "";
export let error: string = "";
</script>
<div>
{#if label.length}
<p class="text-sm font-medium pb-1">
{label}
</p>
{/if}
<div class="flex items-center gap-2">
<input
{name}
class="bg-gray-50 border rounded-md p-3 transition-colors focus:border-primary focus:outline-none focus:ring-0 w-full"
class:border-red-400={error.length > 0}
class:bg-red-50={error.length > 0}
type="date"
bind:value
on:change
/>
</div>
<span class="textfield-error text-xs text-red-400">
{error}
</span>
</div>

View File

@@ -7,7 +7,9 @@
let isOpen = false;
function toggleMenu() {
function toggleMenu(e: MouseEvent) {
e.stopPropagation();
e.preventDefault();
isOpen = !isOpen;
}
@@ -15,8 +17,8 @@
isOpen = false;
}
function handleItemClick(item: { text: string, value: any }) {
dispatch("change", item);
function handleItemClick(item: { text: string; value: any }) {
dispatch("change", item);
closeMenu();
}
</script>
@@ -27,6 +29,7 @@
<button
class="hover:bg-gray-100 w-8 h-8 rounded-full"
on:click={toggleMenu}
type="button"
>
<i class="fa fa-ellipsis-vertical"></i>
</button>
@@ -42,8 +45,8 @@
<li
class="menu-item p-4 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 transition-colors"
tabindex="0"
on:mouseup={() => handleItemClick(item)}
on:keydown={() => handleItemClick(item)}
on:mouseup|stopPropagation={() => handleItemClick(item)}
on:keydown|stopPropagation={() => handleItemClick(item)}
>
{item.text}
</li>

View File

@@ -1,4 +1,5 @@
<script lang="ts">
export let name: string = "";
export let value: any;
export let items: { text: string; value: any }[] = [];
export let label: string = "";
@@ -11,6 +12,7 @@
</p>
{/if}
<select
{name}
class="bg-gray-50 h-10 w-full px-4 border-r-8 border-transparent outline outline-1 outline-gray-200 rounded-md focus:outline-primary transition-colors"
bind:value
>

View File

@@ -1,4 +1,5 @@
<script lang="ts">
export let name: string = "";
export let value: string | number = "";
export let placeholder: string = "";
export let label: string = "";
@@ -17,6 +18,7 @@
<i class="fa fa-{icon}"></i>
{/if}
<input
{name}
class="bg-gray-50 border rounded-md p-3 transition-colors focus:border-primary focus:outline-none focus:ring-0 w-full"
class:border-red-400={error.length > 0}
class:bg-red-50={error.length > 0}

View File

@@ -1,4 +1,5 @@
<script lang="ts">
export let name: string = "";
export let value: string | number = "";
export let placeholder: string = "";
export let rows: number = 3;
@@ -13,6 +14,7 @@
</p>
{/if}
<textarea
{name}
class="bg-gray-50 border rounded-md p-3 resize-none transition-colors focus:border-primary focus:outline-none focus:ring-0 w-full"
{rows}
{placeholder}

View File

@@ -0,0 +1,44 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let src: string;
export let isThumbnail: boolean = false;
const dispatch = createEventDispatcher();
function handleThumbnailClick() {
dispatch("thumbnail", src);
}
function handleDeleteClick() {
dispatch("delete", src);
}
</script>
<div
class="group relative h-32 w-32 rounded-xl bg-cover bg-no-repeat"
style="background-image: url({src});"
>
{#if isThumbnail}
<i
class="fa fa-file-image absolute top-2 right-2 text-primary bg-white rounded-full px-[10px] py-2 shadow-lg"
></i>
{/if}
<div
class="flex opacity-0 group-hover:opacity-100 absolute top-0 w-full h-full bg-white bg-opacity-75 items-center justify-center gap-6 transition-all"
>
<button
type="button"
class="tooltip"
data-title="Make thumbnail"
on:click={handleThumbnailClick}
><i class="fa fa-file-image text-primary"></i></button
>
<button
class="tooltip"
data-title="Delete"
on:click={handleDeleteClick}
type="button"><i class="fa fa-trash text-red-500"></i></button
>
</div>
</div>

View File

@@ -0,0 +1,24 @@
<script lang="ts">
import type { SummitLog } from "$lib/models/summit_log";
import { format, parse } from "date-fns";
import Dropdown from "../base/dropdown.svelte";
export let log: SummitLog;
export let mode: "show" | "edit" = "show";
const dropdownItems = [
{ text: "Edit", value: "edit" },
{ text: "Delete", value: "delete" },
];
</script>
<div class="p-4 my-2 border rounded-xl">
<div class="flex justify-between items-center mb-2">
<h5 class="font-medium mr-2">{format(log.date, 'dd.MM.yyyy')}</h5>
{#if mode == "edit"}
<Dropdown items={dropdownItems} on:change></Dropdown>
{/if}
</div>
<span>{log.text}</span>
</div>

View File

@@ -0,0 +1,67 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { summitLogSchema, type SummitLog } from "$lib/models/summit_log";
import { summitLog } from "$lib/stores/summit_log_store";
import { createForm } from "$lib/vendor/svelte-form-lib/index";
import Datepicker from "../base/datepicker.svelte";
import Modal from "../base/modal.svelte";
import TextField from "../base/text_field.svelte";
import { util } from "$lib/vendor/svelte-form-lib/util";
export let openModal: (() => void) | undefined = undefined;
export let closeModal: (() => void) | undefined = undefined;
const dispatch = createEventDispatcher();
const { form, errors, handleChange, handleSubmit } = createForm<SummitLog>({
initialValues: $summitLog,
validationSchema: summitLogSchema,
onSubmit: async (submittedValues) => {
dispatch("save", submittedValues);
closeModal!();
},
});
$: form.set(util.cloneDeep($summitLog));
</script>
<Modal
id="summit-log-modal"
title="Add Entry"
let:openModal
bind:openModal
bind:closeModal
>
<slot {openModal} />
<form
id="summit-log-form"
slot="content"
class="modal-content space-y-4"
on:submit={handleSubmit}
>
<div class="flex gap-4">
<Datepicker
name="date"
label="Date"
bind:value={$form.date}
error={$errors.date}
on:change={handleChange}
></Datepicker>
<div class="basis-full">
<TextField
name="text"
label="Text"
bind:value={$form.text}
error={$errors.text}
on:change={handleChange}
></TextField>
</div>
</div>
</form>
<div slot="footer" class="flex items-center gap-4">
<button class="btn-secondary" on:click={closeModal}>Cancel</button>
<button class="btn-primary" type="submit" form="summit-log-form"
>Save</button
>
</div>
</Modal>

View File

@@ -1,11 +0,0 @@
<script lang="ts">
import type { SummitLog } from "$lib/models/summit_log";
import { formatISODate } from "$lib/util/format_util";
export let log: SummitLog;
</script>
<div class="p-4 my-2 border rounded-xl">
<h5 class="font-medium mr-2">{formatISODate(log.date)}</h5>
<span>{log.text}</span>
</div>

View File

@@ -2,17 +2,26 @@
import type { Trail } from "$lib/models/trail";
import { getFileURL } from "$lib/util/file_util";
import { formatMeters, formatTimeHHMM } from "$lib/util/format_util";
import Dropdown from "../base/dropdown.svelte";
export let trail: Trail;
const dropdownItems = [
{ text: "Edit", value: "edit" },
{ text: "Delete", value: "delete" },
];
</script>
<div
class="trail-card rounded-2xl shadow-md w-72 overflow-hidden cursor-pointer"
>
<img class="w-full h-48" src={getFileURL(trail, trail.thumbnail)} alt="" />
<div class="trail-card rounded-2xl shadow-md w-72 cursor-pointer">
<div class="w-full h-48 overflow-hidden rounded-t-2xl">
<img src={getFileURL(trail, trail.thumbnail)} alt="" />
</div>
<div class="p-4">
<div>
<h4 class="font-semibold text-lg">{trail.name}</h4>
<div class="flex justify-between items-center">
<h4 class="font-semibold text-lg">{trail.name}</h4>
<Dropdown on:change items={dropdownItems}></Dropdown>
</div>
<h5><i class="fa fa-location-dot mr-3"></i>{trail.location}</h5>
</div>
<div class="flex mt-2 gap-4 text-sm text-gray-500">

View File

@@ -2,11 +2,12 @@
import { Waypoint, waypointSchema } from "$lib/models/waypoint";
import { createEventDispatcher } from "svelte";
import { createForm } from "svelte-forms-lib";
import { createForm } from "$lib/vendor/svelte-form-lib/index";
import Modal from "../base/modal.svelte";
import TextField from "../base/text_field.svelte";
import Textarea from "../base/textarea.svelte";
import { waypoint } from "$lib/stores/waypoint_store";
import { util } from "$lib/vendor/svelte-form-lib/util";
export let openModal: (() => void) | undefined = undefined;
export let closeModal: (() => void) | undefined = undefined;
@@ -21,7 +22,7 @@
closeModal!();
},
});
$: form.set($waypoint);
$: form.set(util.cloneDeep($waypoint));
</script>
<Modal
@@ -41,6 +42,7 @@
<div class="flex gap-4">
<div class="basis-full">
<TextField
name="name"
label="Name"
bind:value={$form.name}
error={$errors.name}
@@ -49,6 +51,7 @@
</div>
<TextField
name="icon"
label="Icon"
bind:value={$form.icon}
icon={$form.icon}
@@ -58,6 +61,7 @@
</div>
<Textarea
name="description"
label="Description"
bind:value={$form.description}
error={$errors.description}
@@ -65,12 +69,14 @@
></Textarea>
<div class="flex gap-4">
<TextField
name="lat"
label="Latitude"
bind:value={$form.lat}
error={$errors.lat}
on:change={handleChange}
></TextField>
<TextField
name="lon"
label="Longitude"
bind:value={$form.lon}
error={$errors.lat}