adds activity timeline
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
switchTabs(0);
|
||||
switchTabs(activeTab ?? 0);
|
||||
});
|
||||
|
||||
function switchTabs(index: number) {
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
const childElement = tabs?.children[index + 1] as HTMLElement;
|
||||
const newWidth = childElement?.getBoundingClientRect().width ?? 0;
|
||||
const newPosition = childElement.offsetLeft;
|
||||
const newPosition = childElement?.offsetLeft;
|
||||
indicatorWidth.set(newWidth);
|
||||
indicatorPosition.set(newPosition);
|
||||
|
||||
|
||||
93
web/src/lib/components/profile/activity_card.svelte
Normal file
93
web/src/lib/components/profile/activity_card.svelte
Normal file
@@ -0,0 +1,93 @@
|
||||
<script lang="ts">
|
||||
import type { Activity } from "$lib/models/activity";
|
||||
import type { UserAnonymous } from "$lib/models/user";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import {
|
||||
formatDistance,
|
||||
formatElevation,
|
||||
formatTimeHHMM,
|
||||
} from "$lib/util/format_util";
|
||||
import { _ } from "svelte-i18n";
|
||||
export let activity: Activity;
|
||||
export let user: UserAnonymous;
|
||||
|
||||
let fullDescription: boolean = false;
|
||||
</script>
|
||||
|
||||
<div class="activity-card p-6 space-y-6 shadow-md rounded-xl">
|
||||
<div class="flex gap-x-4 items-start">
|
||||
<img
|
||||
class="rounded-full w-10 aspect-square overflow-hidden"
|
||||
src={getFileURL(user, user.avatar) ||
|
||||
`https://api.dicebear.com/7.x/initials/svg?seed=${user.username}&backgroundType=gradientLinear`}
|
||||
alt="avatar"
|
||||
/>
|
||||
<div>
|
||||
<a class="underline" href="/profile/{user.id}"> {user.username} </a>
|
||||
{activity.type === "trail" ? "planned" : "completed"}
|
||||
a trail
|
||||
<p class="text-xs text-gray-500 mb-3">
|
||||
{new Date(activity.date).toLocaleDateString(undefined, {
|
||||
month: "long",
|
||||
day: "2-digit",
|
||||
year: "numeric",
|
||||
timeZone: "UTC",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="text-2xl font-semibold !mt-2">{activity.name}</h3>
|
||||
<div class="flex flex-wrap mt-1 gap-x-4 gap-y-2 text-sm text-gray-500">
|
||||
<span
|
||||
><i class="fa fa-left-right mr-2"></i>{formatDistance(
|
||||
activity.distance,
|
||||
)}</span
|
||||
>
|
||||
<span
|
||||
><i class="fa fa-clock mr-2"></i>{formatTimeHHMM(
|
||||
activity.duration,
|
||||
)}</span
|
||||
>
|
||||
<span
|
||||
><i class="fa fa-arrow-trend-up mr-2"></i>{formatElevation(
|
||||
activity.elevation_gain,
|
||||
)}</span
|
||||
>
|
||||
<span
|
||||
><i class="fa fa-arrow-trend-down mr-2"></i>{formatElevation(
|
||||
activity.elevation_loss,
|
||||
)}</span
|
||||
>
|
||||
</div>
|
||||
{#if activity.photos.length}
|
||||
<div
|
||||
class="grid {activity.photos.length > 1
|
||||
? 'grid-cols-[8fr_5fr]'
|
||||
: 'grid-cols-1'}"
|
||||
>
|
||||
{#each activity.photos as photo, i}
|
||||
<img
|
||||
class="object-cover h-full max-h-80 w-full"
|
||||
class:row-span-2={i == 0 && activity.photos.length > 2}
|
||||
src={getFileURL(
|
||||
{ collectionId: activity.type + "s", id: activity.id },
|
||||
photo,
|
||||
)}
|
||||
alt=""
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if activity.description.length}
|
||||
<p class="text-sm whitespace-pre-wrap">
|
||||
{!fullDescription
|
||||
? activity.description?.substring(0, 100)
|
||||
: activity.description}
|
||||
{#if (activity.description?.length ?? 0) > 100 && !fullDescription}
|
||||
<button on:click={() => (fullDescription = true)}>
|
||||
... <span class="underline">{$_("read-more")}</span></button
|
||||
>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -37,6 +37,7 @@
|
||||
export let trail: Trail;
|
||||
export let mode: "overview" | "map" | "list" = "map";
|
||||
export let markers: M.Marker[] = [];
|
||||
export let activeTab = 0;
|
||||
|
||||
const tabs = [
|
||||
$_("description"),
|
||||
@@ -49,7 +50,6 @@
|
||||
const trailIsShared =
|
||||
(trail.expand?.trail_share_via_trail?.length ?? 0) > 0;
|
||||
|
||||
let activeTab = 0;
|
||||
|
||||
let thumbnail = trail.photos.length
|
||||
? getFileURL(trail, trail.photos[trail.thumbnail])
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="table-container w-full border border-input-border rounded-xl overflow-x-scroll"
|
||||
class="table-container w-full border border-input-border rounded-xl overflow-x-scroll overflow-y-clip"
|
||||
>
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
|
||||
Reference in New Issue
Block a user