|
@@ -1,18 +1,30 @@
|
|
|
<script lang="ts">
|
|
|
- import { afterNavigate } from '$app/navigation';
|
|
|
+ import { afterNavigate, goto } from '$app/navigation';
|
|
|
import { page } from '$app/stores';
|
|
|
- import { AlbumResponseDto, AssetResponseDto, ThumbnailFormat } from '@api';
|
|
|
+ import { AlbumResponseDto, api, AssetResponseDto, ThumbnailFormat, UserResponseDto } from '@api';
|
|
|
import { createEventDispatcher, onMount } from 'svelte';
|
|
|
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
|
|
|
+ import Plus from 'svelte-material-icons/Plus.svelte';
|
|
|
import FileImagePlusOutline from 'svelte-material-icons/FileImagePlusOutline.svelte';
|
|
|
import AssetViewer from '../asset-viewer/asset-viewer.svelte';
|
|
|
import CircleAvatar from '../shared-components/circle-avatar.svelte';
|
|
|
import ImmichThumbnail from '../shared-components/immich-thumbnail.svelte';
|
|
|
+ import AssetSelection from './asset-selection.svelte';
|
|
|
+ import _ from 'lodash-es';
|
|
|
+ import { assets } from '$app/paths';
|
|
|
+ import UserSelection from './user-selection-modal.svelte';
|
|
|
+ import AlbumAppBar from './album-app-bar.svelte';
|
|
|
+ import UserSelectionModal from './user-selection-modal.svelte';
|
|
|
|
|
|
const dispatch = createEventDispatcher();
|
|
|
export let album: AlbumResponseDto;
|
|
|
|
|
|
let isShowAssetViewer = false;
|
|
|
+ let isShowAssetSelection = false;
|
|
|
+ let isShowShareUserSelection = false;
|
|
|
+ let isEditingTitle = false;
|
|
|
+ let isCreatingSharedAlbum = false;
|
|
|
+
|
|
|
let selectedAsset: AssetResponseDto;
|
|
|
let currentViewAssetIndex = 0;
|
|
|
|
|
@@ -20,10 +32,20 @@
|
|
|
let thumbnailSize: number = 300;
|
|
|
let border = '';
|
|
|
let backUrl = '/albums';
|
|
|
+ let currentAlbumName = '';
|
|
|
+ let currentUser: UserResponseDto;
|
|
|
+ let bodyElement: HTMLElement;
|
|
|
+
|
|
|
+ $: isOwned = currentUser?.id == album.ownerId;
|
|
|
|
|
|
- afterNavigate(({ from, to }) => {
|
|
|
+ afterNavigate(({ from }) => {
|
|
|
backUrl = from?.pathname ?? '/albums';
|
|
|
+
|
|
|
+ if (from?.pathname === '/sharing') {
|
|
|
+ isCreatingSharedAlbum = true;
|
|
|
+ }
|
|
|
});
|
|
|
+
|
|
|
$: {
|
|
|
if (album.assets.length < 6) {
|
|
|
thumbnailSize = Math.floor(viewWidth / album.assets.length - album.assets.length);
|
|
@@ -36,20 +58,18 @@
|
|
|
const startDate = new Date(album.assets[0].createdAt);
|
|
|
const endDate = new Date(album.assets[album.assets.length - 1].createdAt);
|
|
|
|
|
|
- const startDateString = startDate.toLocaleDateString('us-EN', {
|
|
|
- month: 'short',
|
|
|
- day: 'numeric',
|
|
|
- year: 'numeric'
|
|
|
- });
|
|
|
- const endDateString = endDate.toLocaleDateString('us-EN', {
|
|
|
+ const timeFormatOption: Intl.DateTimeFormatOptions = {
|
|
|
month: 'short',
|
|
|
day: 'numeric',
|
|
|
year: 'numeric'
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ const startDateString = startDate.toLocaleDateString('us-EN', timeFormatOption);
|
|
|
+ const endDateString = endDate.toLocaleDateString('us-EN', timeFormatOption);
|
|
|
return `${startDateString} - ${endDateString}`;
|
|
|
};
|
|
|
|
|
|
- onMount(() => {
|
|
|
+ onMount(async () => {
|
|
|
window.onscroll = (event: Event) => {
|
|
|
if (window.pageYOffset > 80) {
|
|
|
border = 'border border-gray-200 bg-gray-50';
|
|
@@ -57,6 +77,15 @@
|
|
|
border = '';
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+ currentAlbumName = album.albumName;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const { data } = await api.userApi.getMyUserInfo();
|
|
|
+ currentUser = data;
|
|
|
+ } catch (e) {
|
|
|
+ console.log('Error [getMyUserInfo - album-viewer] ', e);
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
const viewAsset = (event: CustomEvent) => {
|
|
@@ -102,62 +131,152 @@
|
|
|
isShowAssetViewer = false;
|
|
|
history.pushState(null, '', `${$page.url.pathname}`);
|
|
|
};
|
|
|
+
|
|
|
+ // Update Album Name
|
|
|
+ $: {
|
|
|
+ if (!isEditingTitle && currentAlbumName != album.albumName && isOwned) {
|
|
|
+ api.albumApi
|
|
|
+ .updateAlbumInfo(album.id, {
|
|
|
+ ownerId: album.ownerId,
|
|
|
+ albumName: album.albumName
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ currentAlbumName = album.albumName;
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ console.log('Error [updateAlbumInfo] ', e);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const createAlbumHandler = async (event: CustomEvent) => {
|
|
|
+ const { assets }: { assets: string[] } = event.detail;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const { data } = await api.albumApi.addAssetsToAlbum(album.id, { assetIds: assets });
|
|
|
+ album = data;
|
|
|
+
|
|
|
+ isShowAssetSelection = false;
|
|
|
+ } catch (e) {
|
|
|
+ console.log('Error [createAlbumHandler] ', e);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const addUserHandler = async (event: CustomEvent) => {
|
|
|
+ const { selectedUsers }: { selectedUsers: UserResponseDto[] } = event.detail;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const { data } = await api.albumApi.addUsersToAlbum(album.id, {
|
|
|
+ sharedUserIds: Array.from(selectedUsers).map((u) => u.id)
|
|
|
+ });
|
|
|
+
|
|
|
+ album = data;
|
|
|
+
|
|
|
+ isShowShareUserSelection = false;
|
|
|
+ } catch (e) {
|
|
|
+ console.log('Error [createAlbumHandler] ', e);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Prevent scrolling when modal is open
|
|
|
+ $: {
|
|
|
+ if (isShowShareUserSelection == true) {
|
|
|
+ document.body.style.overflow = 'hidden';
|
|
|
+ } else {
|
|
|
+ document.body.style.overflow = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
</script>
|
|
|
|
|
|
-<section class="w-screen h-screen bg-immich-bg">
|
|
|
- <div class="fixed top-0 w-full bg-immich-bg z-[100]">
|
|
|
- <div class={`flex justify-between rounded-lg ${border} p-2 mx-2 mt-2 transition-all`}>
|
|
|
- <a sveltekit:prefetch href={backUrl} title="Go Back">
|
|
|
+<svelte:body bind:this={bodyElement} />
|
|
|
+<section class="bg-immich-bg relative">
|
|
|
+ <AlbumAppBar on:close-button-click={() => goto(backUrl)} backIcon={ArrowLeft}>
|
|
|
+ <svelte:fragment slot="trailing">
|
|
|
+ {#if album.assets.length > 0}
|
|
|
<button
|
|
|
id="immich-circle-icon-button"
|
|
|
class={`rounded-full p-3 flex place-items-center place-content-center text-gray-600 transition-all hover:bg-gray-200`}
|
|
|
+ on:click={() => (isShowAssetSelection = true)}
|
|
|
>
|
|
|
- <ArrowLeft size="24" />
|
|
|
+ <FileImagePlusOutline size="24" />
|
|
|
</button>
|
|
|
- </a>
|
|
|
- <div class="right-button-group" title="Add Photos">
|
|
|
+ {/if}
|
|
|
+
|
|
|
+ {#if isCreatingSharedAlbum && album.sharedUsers.length == 0}
|
|
|
<button
|
|
|
- id="immich-circle-icon-button"
|
|
|
- class={`rounded-full p-3 flex place-items-center place-content-center text-gray-600 transition-all hover:bg-gray-200`}
|
|
|
- on:click={() => dispatch('click')}
|
|
|
+ disabled={album.assets.length == 0}
|
|
|
+ on:click={() => (isShowShareUserSelection = true)}
|
|
|
+ class="immich-text-button border bg-immich-primary text-gray-50 hover:bg-immich-primary/75 px-6 text-sm disabled:opacity-25 disabled:bg-gray-500 disabled:cursor-not-allowed"
|
|
|
+ ><span class="px-2">Share</span></button
|
|
|
>
|
|
|
- <FileImagePlusOutline size="24" />
|
|
|
- </button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ {/if}
|
|
|
+ </svelte:fragment>
|
|
|
+ </AlbumAppBar>
|
|
|
|
|
|
- <section class="m-6 py-[72px] px-[160px]">
|
|
|
- <p class="text-6xl text-immich-primary">
|
|
|
- {album.albumName}
|
|
|
- </p>
|
|
|
+ <section class="m-auto my-[160px] w-[60%]">
|
|
|
+ <input
|
|
|
+ on:focus={() => (isEditingTitle = true)}
|
|
|
+ on:blur={() => (isEditingTitle = false)}
|
|
|
+ class={`transition-all text-6xl text-immich-primary w-[99%] border-b-2 border-transparent outline-none ${
|
|
|
+ isOwned ? 'hover:border-gray-400' : 'hover:border-transparent'
|
|
|
+ } focus:outline-none focus:border-b-2 focus:border-immich-primary bg-immich-bg`}
|
|
|
+ type="text"
|
|
|
+ bind:value={album.albumName}
|
|
|
+ disabled={!isOwned}
|
|
|
+ />
|
|
|
|
|
|
- <p class="my-4 text-sm text-gray-500">{getDateRange()}</p>
|
|
|
+ {#if album.assets.length > 0}
|
|
|
+ <p class="my-4 text-sm text-gray-500">{getDateRange()}</p>
|
|
|
+ {/if}
|
|
|
|
|
|
- {#if album.sharedUsers.length > 0}
|
|
|
- <div class="mb-4">
|
|
|
+ {#if album.shared}
|
|
|
+ <div class="my-4 flex">
|
|
|
{#each album.sharedUsers as user}
|
|
|
<span class="mr-1">
|
|
|
<CircleAvatar {user} />
|
|
|
</span>
|
|
|
{/each}
|
|
|
+
|
|
|
+ <button
|
|
|
+ style:display={isOwned ? 'block' : 'none'}
|
|
|
+ on:click={() => (isShowShareUserSelection = true)}
|
|
|
+ title="Add more users"
|
|
|
+ class="h-12 w-12 border bg-white transition-colors hover:bg-gray-300 text-3xl flex place-items-center place-content-center rounded-full"
|
|
|
+ >+</button
|
|
|
+ >
|
|
|
</div>
|
|
|
{/if}
|
|
|
|
|
|
- <div class="flex flex-wrap gap-1 w-full" bind:clientWidth={viewWidth}>
|
|
|
- {#each album.assets as asset}
|
|
|
- {#if album.assets.length < 7}
|
|
|
- <ImmichThumbnail
|
|
|
- {asset}
|
|
|
- {thumbnailSize}
|
|
|
- format={ThumbnailFormat.Jpeg}
|
|
|
- on:viewAsset={viewAsset}
|
|
|
- />
|
|
|
- {:else}
|
|
|
- <ImmichThumbnail {asset} {thumbnailSize} on:viewAsset={viewAsset} />
|
|
|
- {/if}
|
|
|
- {/each}
|
|
|
- </div>
|
|
|
+ {#if album.assets.length > 0}
|
|
|
+ <div class="flex flex-wrap gap-1 w-full" bind:clientWidth={viewWidth}>
|
|
|
+ {#each album.assets as asset}
|
|
|
+ {#if album.assets.length < 7}
|
|
|
+ <ImmichThumbnail
|
|
|
+ {asset}
|
|
|
+ {thumbnailSize}
|
|
|
+ format={ThumbnailFormat.Jpeg}
|
|
|
+ on:click={viewAsset}
|
|
|
+ />
|
|
|
+ {:else}
|
|
|
+ <ImmichThumbnail {asset} {thumbnailSize} on:click={viewAsset} />
|
|
|
+ {/if}
|
|
|
+ {/each}
|
|
|
+ </div>
|
|
|
+ {:else}
|
|
|
+ <!-- Album is empty - Show asset selectection buttons -->
|
|
|
+ <section id="empty-album" class=" mt-[200px] flex place-content-center place-items-center">
|
|
|
+ <div class="w-[300px]">
|
|
|
+ <p class="text-xs">ADD PHOTOS</p>
|
|
|
+ <button
|
|
|
+ on:click={() => (isShowAssetSelection = true)}
|
|
|
+ class="w-full py-8 border bg-white rounded-md mt-5 flex place-items-center gap-6 px-8 transition-all hover:bg-gray-100 hover:text-immich-primary"
|
|
|
+ >
|
|
|
+ <span><Plus color="#4250af" size="24" /> </span>
|
|
|
+ <span class="text-lg text-immich-fg">Select photos</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+ {/if}
|
|
|
</section>
|
|
|
</section>
|
|
|
|
|
@@ -170,3 +289,19 @@
|
|
|
on:close={closeViewer}
|
|
|
/>
|
|
|
{/if}
|
|
|
+
|
|
|
+{#if isShowAssetSelection}
|
|
|
+ <AssetSelection
|
|
|
+ assetsInAlbum={album.assets}
|
|
|
+ on:go-back={() => (isShowAssetSelection = false)}
|
|
|
+ on:create-album={createAlbumHandler}
|
|
|
+ />
|
|
|
+{/if}
|
|
|
+
|
|
|
+{#if isShowShareUserSelection}
|
|
|
+ <UserSelectionModal
|
|
|
+ on:close={() => (isShowShareUserSelection = false)}
|
|
|
+ on:add-user={addUserHandler}
|
|
|
+ sharedUsersInAlbum={new Set(album.sharedUsers)}
|
|
|
+ />
|
|
|
+{/if}
|