adds video support
This commit is contained in:
@@ -167,12 +167,11 @@
|
||||
}
|
||||
});
|
||||
$effect(() => {
|
||||
if (waypoints) {
|
||||
untrack(() => {
|
||||
showWaypoints();
|
||||
refreshElevationProfile();
|
||||
});
|
||||
}
|
||||
waypoints;
|
||||
untrack(() => {
|
||||
showWaypoints();
|
||||
refreshElevationProfile();
|
||||
});
|
||||
});
|
||||
|
||||
function getData(trails: Trail[]) {
|
||||
@@ -280,7 +279,7 @@
|
||||
right: 16,
|
||||
bottom:
|
||||
16 +
|
||||
(epc?.isProfileShown
|
||||
(epc?.isProfileShown && !elevationProfileContainer
|
||||
? map!.getContainer().clientHeight * 0.3
|
||||
: 0),
|
||||
},
|
||||
@@ -663,6 +662,13 @@
|
||||
markers.push(marker);
|
||||
}
|
||||
}
|
||||
markers = markers.filter((marker) => {
|
||||
if (!waypoints.find((w) => w.id == marker._element.id)) {
|
||||
marker.remove();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function hideWaypoints() {
|
||||
|
||||
@@ -87,7 +87,10 @@
|
||||
continue;
|
||||
}
|
||||
let photoFile = file;
|
||||
if (!file.type.startsWith("image")) {
|
||||
if (
|
||||
!file.type.startsWith("image") &&
|
||||
!["video/mp4", "video/ogg", "video/webm"].includes(file.type)
|
||||
) {
|
||||
continue;
|
||||
} else if (file.type === "image/heic") {
|
||||
const heic2any = (await import("heic2any")).default;
|
||||
@@ -151,7 +154,7 @@
|
||||
<input
|
||||
type="file"
|
||||
id="{id}-photo-input"
|
||||
accept="image/*"
|
||||
accept="image/*,video/mp4"
|
||||
multiple={true}
|
||||
style="display: none;"
|
||||
onchange={() => handlePhotoSelection()}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import { pb } from "$lib/pocketbase";
|
||||
import { theme } from "$lib/stores/theme_store";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import { getFileURL, isVideoURL } from "$lib/util/file_util";
|
||||
import {
|
||||
formatDistance,
|
||||
formatElevation,
|
||||
@@ -55,7 +55,24 @@
|
||||
<div
|
||||
class="relative w-full basis-full max-h-48 overflow-hidden rounded-t-2xl"
|
||||
>
|
||||
<img loading="lazy" class="w-full h-full" id="header-img" src={thumbnail} alt="" />
|
||||
{#if isVideoURL(thumbnail)}
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video
|
||||
id="header-img"
|
||||
class="w-full h-full object-cover"
|
||||
autoplay
|
||||
loop
|
||||
src={thumbnail}
|
||||
></video>
|
||||
{:else}
|
||||
<img
|
||||
loading="lazy"
|
||||
class="w-full h-full"
|
||||
id="header-img"
|
||||
src={thumbnail}
|
||||
alt=""
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if (trail.public || trailIsShared) && pb.authStore.model}
|
||||
<div
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
comments_update,
|
||||
} from "$lib/stores/comment_store";
|
||||
import { currentUser } from "$lib/stores/user_store";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import { getFileURL, isVideoURL } from "$lib/util/file_util";
|
||||
import {
|
||||
formatDistance,
|
||||
formatElevation,
|
||||
@@ -172,12 +172,23 @@
|
||||
>
|
||||
<div class="trail-info-panel-header">
|
||||
<section class="relative h-80">
|
||||
<img
|
||||
class="w-full h-80"
|
||||
class:rounded-t-3xl={mode !== "list"}
|
||||
src={thumbnail}
|
||||
alt=""
|
||||
/>
|
||||
{#if isVideoURL(thumbnail)}
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video
|
||||
class="w-full h-80 object-cover rounded-t-3xl"
|
||||
autoplay
|
||||
loop
|
||||
src={thumbnail}
|
||||
></video>
|
||||
{:else}
|
||||
<img
|
||||
class="w-full h-80"
|
||||
class:rounded-t-3xl={mode !== "list"}
|
||||
src={thumbnail}
|
||||
alt=""
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="absolute bottom-0 w-full h-full bg-gradient-to-b from-transparent to-black opacity-60"
|
||||
></div>
|
||||
@@ -215,7 +226,10 @@
|
||||
class="flex absolute justify-between items-end w-full bottom-8 left-0 px-8 gap-y-4"
|
||||
>
|
||||
<div class="text-white overflow-hidden">
|
||||
<h4 title={trail.name} class="text-4xl font-bold line-clamp-3">
|
||||
<h4
|
||||
title={trail.name}
|
||||
class="text-4xl font-bold line-clamp-3"
|
||||
>
|
||||
{trail.name}
|
||||
</h4>
|
||||
{#if trail.date}
|
||||
@@ -414,12 +428,27 @@
|
||||
{#each trail.photos ?? [] as photo, i}
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<img
|
||||
class="rounded-xl cursor-pointer hover:scale-105 transition-transform"
|
||||
onclick={() => gallery.openGallery(i)}
|
||||
src={getFileURL(trail, photo)}
|
||||
alt=""
|
||||
/>
|
||||
{#if isVideoURL(photo)}
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video
|
||||
controls={false}
|
||||
loop
|
||||
class="rounded-xl cursor-pointer hover:scale-105 transition-transform"
|
||||
onclick={() => gallery.openGallery(i)}
|
||||
onmouseenter={(e) =>
|
||||
(e.target as any).play()}
|
||||
onmouseleave={(e) =>
|
||||
(e.target as any).pause()}
|
||||
src={getFileURL(trail, photo)}
|
||||
></video>
|
||||
{:else}
|
||||
<img
|
||||
class="rounded-xl cursor-pointer hover:scale-105 transition-transform"
|
||||
onclick={() => gallery.openGallery(i)}
|
||||
src={getFileURL(trail, photo)}
|
||||
alt=""
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import { pb } from "$lib/pocketbase";
|
||||
import { theme } from "$lib/stores/theme_store";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import { getFileURL, isVideoURL } from "$lib/util/file_util";
|
||||
import {
|
||||
formatDistance,
|
||||
formatElevation,
|
||||
@@ -12,7 +12,6 @@
|
||||
} from "$lib/util/format_util";
|
||||
import { _ } from "svelte-i18n";
|
||||
import ShareInfo from "../share_info.svelte";
|
||||
|
||||
|
||||
interface Props {
|
||||
trail: Trail;
|
||||
@@ -21,18 +20,34 @@
|
||||
|
||||
let { trail, showDescription = true }: Props = $props();
|
||||
|
||||
let thumbnail = $derived(trail.photos.length
|
||||
? getFileURL(trail, trail.photos[trail.thumbnail ?? 0])
|
||||
: $theme === "light"
|
||||
? emptyStateTrailLight
|
||||
: emptyStateTrailDark);
|
||||
let thumbnail = $derived(
|
||||
trail.photos.length
|
||||
? getFileURL(trail, trail.photos[trail.thumbnail ?? 0])
|
||||
: $theme === "light"
|
||||
? emptyStateTrailLight
|
||||
: emptyStateTrailDark,
|
||||
);
|
||||
</script>
|
||||
|
||||
<li
|
||||
class="flex gap-8 p-4 rounded-xl border border-input-border cursor-pointer hover:bg-secondary-hover transition-colors items-center"
|
||||
>
|
||||
<div class="shrink-0">
|
||||
<img class="h-28 w-28 object-cover rounded-xl" src={thumbnail} alt="" />
|
||||
{#if isVideoURL(thumbnail)}
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video
|
||||
class="h-28 w-28 object-cover rounded-xl"
|
||||
autoplay
|
||||
loop
|
||||
src={thumbnail}
|
||||
></video>
|
||||
{:else}
|
||||
<img
|
||||
class="h-28 w-28 object-cover rounded-xl"
|
||||
src={thumbnail}
|
||||
alt=""
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="min-w-0 basis-full">
|
||||
<div class="flex items-center gap-4">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import { getFileURL, isVideoURL } from "$lib/util/file_util";
|
||||
import { formatDistance } from "$lib/util/format_util";
|
||||
import { _ } from "svelte-i18n";
|
||||
import PhotoGallery from "../photo_gallery.svelte";
|
||||
@@ -52,23 +52,40 @@
|
||||
: 'grid-cols-1'} cursor-pointer"
|
||||
>
|
||||
{#each wp.photos as photo, j}
|
||||
<img
|
||||
onclick={() => gallery[i].openGallery(j)}
|
||||
role="presentation"
|
||||
class="w-full object-cover {j == 0 &&
|
||||
wp.photos.length > 2
|
||||
? 'row-span-2 h-80'
|
||||
: 'h-[159.5px]'}"
|
||||
src={getFileURL(wp, photo)}
|
||||
alt=""
|
||||
/>
|
||||
{#if isVideoURL(photo)}
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video
|
||||
controls={false}
|
||||
loop
|
||||
class="w-full object-cover {j == 0 &&
|
||||
wp.photos.length > 2
|
||||
? 'row-span-2 h-80'
|
||||
: 'h-[159.5px]'}"
|
||||
onclick={() => gallery[i].openGallery(j)}
|
||||
onmouseenter={(e) => (e.target as any).play()}
|
||||
onmouseleave={(e) => (e.target as any).pause()}
|
||||
src={getFileURL(wp, photo)}
|
||||
></video>
|
||||
{:else}
|
||||
<img
|
||||
onclick={() => gallery[i].openGallery(j)}
|
||||
role="presentation"
|
||||
class="w-full object-cover {j == 0 &&
|
||||
wp.photos.length > 2
|
||||
? 'row-span-2 h-80'
|
||||
: 'h-[159.5px]'}"
|
||||
src={getFileURL(wp, photo)}
|
||||
alt=""
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="p-4">
|
||||
<h5 class="text-xl font-semibold">{wp.name}</h5>
|
||||
<span class="text-sm text-gray-500"
|
||||
><i class="fa fa-location-dot mr-1"></i> {wp.lat.toFixed(5)}, {wp.lon.toFixed(5)}</span
|
||||
><i class="fa fa-location-dot mr-1"></i>
|
||||
{wp.lat.toFixed(5)}, {wp.lon.toFixed(5)}</span
|
||||
>
|
||||
<p class="whitespace-pre-line">
|
||||
{wp.description}
|
||||
|
||||
Reference in New Issue
Block a user