2022-05-21 02:23:55 -05:00
< script context = "module" lang = "ts" >
2022-05-21 23:28:02 -05:00
export const prerender = false;
2022-05-21 02:23:55 -05:00
import type { Load } from '@sveltejs/kit';
2022-08-06 18:14:54 -05:00
import { setAssetInfo } from '$lib/stores/assets';
2022-08-08 22:06:11 -05:00
2022-08-07 18:36:34 -05:00
export const load: Load = async ({ fetch , session } ) => {
if (!browser && !session.user) {
return {
status: 302,
redirect: '/auth/login'
};
}
2022-05-21 02:23:55 -05:00
2022-07-26 12:28:07 -05:00
try {
2022-08-06 18:14:54 -05:00
const [userInfo, assets] = await Promise.all([
fetch('/data/user/get-my-user-info').then((r) => r.json()),
fetch('/data/asset/get-all-assets').then((r) => r.json())
]);
setAssetInfo(assets);
2022-07-26 12:28:07 -05:00
return {
status: 200,
props: {
2022-08-06 18:14:54 -05:00
user: userInfo
2022-07-26 12:28:07 -05:00
}
};
} catch (e) {
2022-08-06 18:14:54 -05:00
console.log('ERROR load photos index');
2022-05-21 02:23:55 -05:00
return {
status: 302,
2022-07-15 23:18:17 -05:00
redirect: '/auth/login'
2022-05-21 02:23:55 -05:00
};
}
};
< / script >
< script lang = "ts" >
2022-07-16 23:52:00 -05:00
import NavigationBar from '$lib/components/shared-components/navigation-bar.svelte';
2022-05-27 14:02:06 -05:00
import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
2022-06-03 11:04:30 -05:00
import { fly } from 'svelte/transition';
2022-08-08 22:06:11 -05:00
import { assetsGroupByDate , flattenAssetGroupByDate , assets } from '$lib/stores/assets';
2022-07-16 23:52:00 -05:00
import ImmichThumbnail from '$lib/components/shared-components/immich-thumbnail.svelte';
2022-05-21 16:50:56 -05:00
import moment from 'moment';
2022-07-18 00:22:39 -05:00
import AssetViewer from '$lib/components/asset-viewer/asset-viewer.svelte';
2022-07-26 20:53:25 -05:00
import { openFileUploadDialog , UploadType } from '$lib/utils/file-uploader';
2022-08-08 22:06:11 -05:00
import { api , AssetResponseDto , UserResponseDto } from '@api';
2022-07-16 23:52:00 -05:00
import SideBar from '$lib/components/shared-components/side-bar/side-bar.svelte';
2022-08-08 22:06:11 -05:00
import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
import CircleIconButton from '$lib/components/shared-components/circle-icon-button.svelte';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import Close from 'svelte-material-icons/Close.svelte';
2022-08-07 18:36:34 -05:00
import { browser } from '$app/env';
2022-08-08 22:06:11 -05:00
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
2022-05-21 02:23:55 -05:00
2022-07-26 12:28:07 -05:00
export let user: UserResponseDto;
2022-07-08 21:26:50 -05:00
2022-05-27 14:02:06 -05:00
let selectedGroupThumbnail: number | null;
let isMouseOverGroup: boolean;
2022-07-18 00:22:39 -05:00
2022-08-08 22:06:11 -05:00
let multiSelectedAssets = new Set< AssetResponseDto > ();
$: isMultiSelectionMode = multiSelectedAssets.size > 0;
let selectedGroup: Set< number > = new Set();
let existingGroup: Set< number > = new Set();
2022-05-27 14:02:06 -05:00
$: if (isMouseOverGroup == false) {
selectedGroupThumbnail = null;
}
2022-07-18 00:22:39 -05:00
let isShowAssetViewer = false;
2022-05-27 14:02:06 -05:00
let currentViewAssetIndex = 0;
2022-07-18 00:22:39 -05:00
let selectedAsset: AssetResponseDto;
2022-05-21 02:23:55 -05:00
2022-05-27 14:02:06 -05:00
const thumbnailMouseEventHandler = (event: CustomEvent) => {
const { selectedGroupIndex } : { selectedGroupIndex : number } = event.detail;
selectedGroupThumbnail = selectedGroupIndex;
};
const viewAssetHandler = (event: CustomEvent) => {
2022-07-23 23:23:14 -05:00
const { asset } : { asset : AssetResponseDto } = event.detail;
2022-05-27 14:02:06 -05:00
2022-07-23 23:23:14 -05:00
currentViewAssetIndex = $flattenAssetGroupByDate.findIndex((a) => a.id == asset.id);
2022-07-18 00:22:39 -05:00
selectedAsset = $flattenAssetGroupByDate[currentViewAssetIndex];
isShowAssetViewer = true;
pushState(selectedAsset.id);
2022-06-19 08:16:35 -05:00
};
2022-07-18 00:22:39 -05:00
const navigateAssetForward = () => {
try {
if (currentViewAssetIndex < $flattenAssetGroupByDate.length - 1) {
currentViewAssetIndex++;
selectedAsset = $flattenAssetGroupByDate[currentViewAssetIndex];
pushState(selectedAsset.id);
}
} catch (e) {
console.log('Error navigating asset forward', e);
}
};
const navigateAssetBackward = () => {
try {
if (currentViewAssetIndex > 0) {
currentViewAssetIndex--;
selectedAsset = $flattenAssetGroupByDate[currentViewAssetIndex];
pushState(selectedAsset.id);
}
} catch (e) {
console.log('Error navigating asset backward', e);
}
};
const pushState = (assetId: string) => {
// add a URL to the browser's history
// changes the current URL in the address bar but doesn't perform any SvelteKit navigation
history.pushState(null, '', `/photos/${ assetId } `);
};
const closeViewer = () => {
isShowAssetViewer = false;
history.pushState(null, '', `/photos`);
};
2022-08-08 22:06:11 -05:00
const selectAssetHandler = (asset: AssetResponseDto, groupIndex: number) => {
let temp = new Set(multiSelectedAssets);
if (multiSelectedAssets.has(asset)) {
temp.delete(asset);
const tempSelectedGroup = new Set(selectedGroup);
tempSelectedGroup.delete(groupIndex);
selectedGroup = tempSelectedGroup;
} else {
temp.add(asset);
}
multiSelectedAssets = temp;
// Check if all assets are selected in a group to toggle the group selection's icon
if (!selectedGroup.has(groupIndex)) {
const assetsInGroup = $assetsGroupByDate[groupIndex];
let selectedAssetsInGroupCount = 0;
assetsInGroup.forEach((asset) => {
if (multiSelectedAssets.has(asset)) {
selectedAssetsInGroupCount++;
}
});
// if all assets are selected in a group, add the group to selected group
if (selectedAssetsInGroupCount == assetsInGroup.length) {
selectedGroup = selectedGroup.add(groupIndex);
}
}
};
const clearMultiSelectAssetAssetHandler = () => {
multiSelectedAssets = new Set();
selectedGroup = new Set();
existingGroup = new Set();
};
const selectAssetGroupHandler = (groupIndex: number) => {
if (existingGroup.has(groupIndex)) return;
let tempSelectedGroup = new Set(selectedGroup);
let tempSelectedAsset = new Set(multiSelectedAssets);
if (selectedGroup.has(groupIndex)) {
tempSelectedGroup.delete(groupIndex);
tempSelectedAsset.forEach((asset) => {
if ($assetsGroupByDate[groupIndex].find((a) => a.id == asset.id)) {
tempSelectedAsset.delete(asset);
}
});
} else {
tempSelectedGroup.add(groupIndex);
tempSelectedAsset = new Set([...multiSelectedAssets, ...$assetsGroupByDate[groupIndex]]);
}
multiSelectedAssets = tempSelectedAsset;
selectedGroup = tempSelectedGroup;
};
const deleteSelectedAssetHandler = async () => {
try {
if (
window.confirm(
2022-08-08 22:13:36 -05:00
`Caution! Are you sure you want to delete ${ multiSelectedAssets . size } assets? This step also deletes assets in the album(s) to which they belong. You can not undo this action!`
2022-08-08 22:06:11 -05:00
)
) {
const { data : deletedAssets } = await api.assetApi.deleteAsset({
ids: Array.from(multiSelectedAssets).map((a) => a.id)
});
for (const asset of deletedAssets) {
if (asset.status == 'SUCCESS') {
$assets = $assets.filter((a) => a.id !== asset.id);
}
}
clearMultiSelectAssetAssetHandler();
}
} catch (e) {
console.log('Error deleteSelectedAssetHandler', e);
}
};
2022-05-21 02:23:55 -05:00
< / script >
< svelte:head >
2022-07-15 23:18:17 -05:00
< title > Photos - Immich< / title >
2022-05-21 02:23:55 -05:00
< / svelte:head >
< section >
2022-08-08 22:06:11 -05:00
{ #if isMultiSelectionMode }
< ControlAppBar
on:close-button-click={ clearMultiSelectAssetAssetHandler }
backIcon={ Close }
tailwindClasses={ 'bg-white shadow-md' }
>
< svelte:fragment slot = "leading" >
< p class = "font-medium text-immich-primary" > Selected { multiSelectedAssets . size } </ p >
< / svelte:fragment >
< svelte:fragment slot = "trailing" >
< CircleIconButton
title="Delete"
logo={ DeleteOutline }
on:click={ deleteSelectedAssetHandler }
/>
< / svelte:fragment >
< / ControlAppBar >
{ /if }
{ #if ! isMultiSelectionMode }
< NavigationBar { user } on:uploadClicked = {() => openFileUploadDialog ( UploadType . GENERAL )} / >
{ /if }
2022-05-21 02:23:55 -05:00
< / section >
2022-06-19 08:16:35 -05:00
< section class = "grid grid-cols-[250px_auto] relative pt-[72px] h-screen bg-immich-bg" >
2022-07-15 23:18:17 -05:00
< SideBar / >
2022-05-21 02:23:55 -05:00
2022-05-27 14:02:06 -05:00
<!-- Main Section -->
2022-07-23 13:08:49 -05:00
< section class = "overflow-y-auto relative immich-scrollbar" >
2022-06-19 08:16:35 -05:00
< section id = "assets-content" class = "relative pt-8 pl-4 mb-12 bg-immich-bg" >
2022-05-27 14:02:06 -05:00
< section id = "image-grid" class = "flex flex-wrap gap-14" >
{ #each $assetsGroupByDate as assetsInDateGroup , groupIndex }
<!-- Asset Group By Date -->
< div
class="flex flex-col"
on:mouseenter={() => ( isMouseOverGroup = true )}
on:mouseleave={() => ( isMouseOverGroup = false )}
>
<!-- Date group title -->
2022-06-19 08:16:35 -05:00
< p class = "font-medium text-sm text-immich-fg mb-2 flex place-items-center h-6" >
2022-08-09 19:10:55 -05:00
{ #if ( selectedGroupThumbnail === groupIndex && isMouseOverGroup ) || selectedGroup . has ( groupIndex )}
2022-05-27 14:02:06 -05:00
< div
in:fly={{ x : - 24 , duration : 200 , opacity : 0.5 }}
out:fly={{ x : - 24 , duration : 200 }}
class="inline-block px-2 hover:cursor-pointer"
2022-08-08 22:06:11 -05:00
on:click={() => selectAssetGroupHandler ( groupIndex )}
2022-05-27 14:02:06 -05:00
>
2022-08-08 22:06:11 -05:00
{ #if selectedGroup . has ( groupIndex )}
< CheckCircle size = "24" color = "#4250af" / >
{ :else if existingGroup . has ( groupIndex )}
< CheckCircle size = "24" color = "#757575" / >
{ : else }
< CircleOutline size = "24" color = "#757575" / >
{ /if }
2022-05-27 14:02:06 -05:00
< / div >
{ /if }
2022-05-21 16:50:56 -05:00
{ moment ( assetsInDateGroup [ 0 ]. createdAt ). format ( 'ddd, MMM DD YYYY' )}
< / p >
2022-05-27 14:02:06 -05:00
<!-- Image grid -->
2022-06-19 08:16:35 -05:00
< div class = "flex flex-wrap gap-[2px]" >
2022-05-21 16:50:56 -05:00
{ #each assetsInDateGroup as asset }
2022-07-23 23:23:14 -05:00
{ #key asset . id }
< ImmichThumbnail
{ asset }
on:mouseEvent={ thumbnailMouseEventHandler }
2022-08-08 22:06:11 -05:00
on:click={( event ) =>
isMultiSelectionMode
? selectAssetHandler(asset, groupIndex)
: viewAssetHandler(event)}
on:select={() => selectAssetHandler ( asset , groupIndex )}
selected={ multiSelectedAssets . has ( asset )}
2022-07-23 23:23:14 -05:00
{ groupIndex }
/>
{ /key }
2022-05-21 16:50:56 -05:00
{ /each }
< / div >
< / div >
{ /each }
< / section >
2022-05-21 02:23:55 -05:00
< / section >
< / section >
< / section >
2022-05-27 14:02:06 -05:00
<!-- Overlay Asset Viewer -->
2022-07-18 00:22:39 -05:00
{ #if isShowAssetViewer }
2022-06-03 11:04:30 -05:00
< AssetViewer
2022-07-18 00:22:39 -05:00
asset={ selectedAsset }
on:navigate-backward={ navigateAssetBackward }
on:navigate-forward={ navigateAssetForward }
on:close={ closeViewer }
2022-06-03 11:04:30 -05:00
/>
2022-05-27 14:02:06 -05:00
{ /if }