feat(web): revamp places (#12219)
* revamp places * add english translations * migrate places page and components to svelte 5 * fix lint * chore: cleanup --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
<script lang="ts">
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { mdiMapMarkerOff } from '@mdi/js';
|
||||
import PlacesControls from '$lib/components/places-page/places-controls.svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { getMetadataSearchQuery } from '$lib/utils/metadata-search';
|
||||
import { AssetMediaSize, type AssetResponseDto } from '@immich/sdk';
|
||||
import { type AssetResponseDto } from '@immich/sdk';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { getAssetThumbnailUrl } from '$lib/utils';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import Places from '$lib/components/places-page/places-list.svelte';
|
||||
import { placesViewSettings } from '$lib/stores/preferences.store';
|
||||
|
||||
interface Props {
|
||||
data: PageData;
|
||||
@@ -21,43 +20,33 @@
|
||||
};
|
||||
};
|
||||
|
||||
let searchQuery = $state('');
|
||||
let searchResultCount = $state(0);
|
||||
let placesGroups: string[] = $state([]);
|
||||
|
||||
let places = $derived(data.items.filter((item): item is AssetWithCity => !!item.exifInfo?.city));
|
||||
let hasPlaces = $derived(places.length > 0);
|
||||
let countVisiblePlaces = $derived(searchQuery ? searchResultCount : places.length);
|
||||
|
||||
let innerHeight: number = $state(0);
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerHeight />
|
||||
|
||||
<UserPageLayout title={$t('places')}>
|
||||
{#if hasPlaces}
|
||||
<div class="flex flex-row flex-wrap gap-4">
|
||||
{#each places as item (item.id)}
|
||||
{@const city = item.exifInfo.city}
|
||||
<a class="relative" href="{AppRoute.SEARCH}?{getMetadataSearchQuery({ city })}" draggable="false">
|
||||
<div
|
||||
class="flex w-[calc((100vw-(72px+5rem))/2)] max-w-[156px] justify-center overflow-hidden rounded-xl brightness-75 filter"
|
||||
>
|
||||
<img
|
||||
src={getAssetThumbnailUrl({ id: item.id, size: AssetMediaSize.Thumbnail })}
|
||||
alt={city}
|
||||
class="object-cover w-[156px] h-[156px]"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="w-100 absolute bottom-2 w-full text-ellipsis px-1 text-center text-sm font-medium capitalize text-white backdrop-blur-[1px] hover:cursor-pointer"
|
||||
>
|
||||
{city}
|
||||
</span>
|
||||
</a>
|
||||
{/each}
|
||||
<UserPageLayout
|
||||
title={$t('places')}
|
||||
description={countVisiblePlaces === 0 && !searchQuery ? undefined : `(${countVisiblePlaces.toLocaleString($locale)})`}
|
||||
>
|
||||
{#snippet buttons()}
|
||||
<div class="flex place-items-center gap-2">
|
||||
<PlacesControls {placesGroups} bind:searchQuery />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white">
|
||||
<div class="flex flex-col content-center items-center text-center">
|
||||
<Icon path={mdiMapMarkerOff} size="3.5em" />
|
||||
<p class="mt-5 text-3xl font-medium">{$t('no_places')}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
<Places
|
||||
{places}
|
||||
userSettings={$placesViewSettings}
|
||||
{searchQuery}
|
||||
bind:searchResultCount
|
||||
bind:placesGroupIds={placesGroups}
|
||||
/>
|
||||
</UserPageLayout>
|
||||
|
||||
Reference in New Issue
Block a user