mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
Show assets on web (#168)
* Implemented lazy loading thumbnail * Display assets as date-time grouping * Update Readme * Modify GitHub action to run from the latest update
This commit is contained in:
parent
171e7ffa77
commit
6023c3c624
14 changed files with 350 additions and 752 deletions
46
web/src/lib/components/photos/immich-thumbnail.svelte
Normal file
46
web/src/lib/components/photos/immich-thumbnail.svelte
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<script lang="ts">
|
||||
import type { ImmichAsset } from '../../models/immich-asset';
|
||||
import { session } from '$app/stores';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { serverEndpoint } from '../../constants';
|
||||
import IntersectionObserver from '$lib/components/photos/intersection-observer.svelte';
|
||||
|
||||
export let asset: ImmichAsset;
|
||||
let imageContent: string;
|
||||
|
||||
const loadImageData = async () => {
|
||||
if ($session.user) {
|
||||
const res = await fetch(serverEndpoint + '/asset/thumbnail/' + asset.id, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: 'bearer ' + $session.user.accessToken,
|
||||
},
|
||||
});
|
||||
|
||||
imageContent = URL.createObjectURL(await res.blob());
|
||||
|
||||
return imageContent;
|
||||
}
|
||||
};
|
||||
|
||||
onDestroy(() => URL.revokeObjectURL(imageContent));
|
||||
</script>
|
||||
|
||||
<IntersectionObserver once={true} let:intersecting>
|
||||
<div class="h-[200px] w-[200px] bg-gray-100">
|
||||
{#if intersecting}
|
||||
{#await loadImageData()}
|
||||
<div class="bg-immich-primary/10 h-[200px] w-[200px] flex place-items-center place-content-center">...</div>
|
||||
{:then imageData}
|
||||
<img
|
||||
in:fade={{ duration: 200 }}
|
||||
src={imageData}
|
||||
alt={asset.id}
|
||||
class="object-cover h-[200px] w-[200px] transition-all duration-100"
|
||||
loading="lazy"
|
||||
/>
|
||||
{/await}
|
||||
{/if}
|
||||
</div>
|
||||
</IntersectionObserver>
|
||||
55
web/src/lib/components/photos/intersection-observer.svelte
Normal file
55
web/src/lib/components/photos/intersection-observer.svelte
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let once = false;
|
||||
export let top = 0;
|
||||
export let bottom = 0;
|
||||
export let left = 0;
|
||||
export let right = 0;
|
||||
|
||||
let intersecting = false;
|
||||
let container: any;
|
||||
|
||||
onMount(() => {
|
||||
if (typeof IntersectionObserver !== 'undefined') {
|
||||
const rootMargin = `${bottom}px ${left}px ${top}px ${right}px`;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
intersecting = entries[0].isIntersecting;
|
||||
if (intersecting && once) {
|
||||
observer.unobserve(container);
|
||||
}
|
||||
},
|
||||
{
|
||||
rootMargin,
|
||||
},
|
||||
);
|
||||
|
||||
observer.observe(container);
|
||||
return () => observer.unobserve(container);
|
||||
}
|
||||
|
||||
// The following is a fallback for older browsers
|
||||
function handler() {
|
||||
const bcr = container.getBoundingClientRect();
|
||||
|
||||
intersecting =
|
||||
bcr.bottom + bottom > 0 &&
|
||||
bcr.right + right > 0 &&
|
||||
bcr.top - top < window.innerHeight &&
|
||||
bcr.left - left < window.innerWidth;
|
||||
|
||||
if (intersecting && once) {
|
||||
window.removeEventListener('scroll', handler);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', handler);
|
||||
return () => window.removeEventListener('scroll', handler);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div bind:this={container}>
|
||||
<slot {intersecting} />
|
||||
</div>
|
||||
|
|
@ -16,10 +16,10 @@
|
|||
<div class="flex border place-items-center px-6 py-2 ">
|
||||
<a class="flex gap-2 place-items-center hover:cursor-pointer" href="/photos">
|
||||
<img src="/immich-logo.svg" alt="immich logo" height="35" width="35" />
|
||||
<h1 class="font-immich-title text-2xl text-immich-primary">Immich</h1>
|
||||
<h1 class="font-immich-title text-2xl text-immich-primary">IMMICH</h1>
|
||||
</a>
|
||||
<div class="flex-1 ml-24">
|
||||
<div class="w-[50%] border rounded-md bg-gray-200 px-8 py-4">Search</div>
|
||||
<input class="w-[50%] border rounded-md bg-gray-200 px-8 py-4" placeholder="Search - Coming soon" />
|
||||
</div>
|
||||
<section class="flex gap-6 place-items-center">
|
||||
<!-- <div>Upload</div> -->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue