mirror of
https://github.com/immich-app/immich.git
synced 2026-03-22 05:39:38 +03:00
120 lines
4.3 KiB
Svelte
120 lines
4.3 KiB
Svelte
<script lang="ts">
|
|
import AssetLayout from '$lib/components/timeline/AssetLayout.svelte';
|
|
import { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte';
|
|
import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte';
|
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
|
import { assetsSnapshot, filterRenderable } from '$lib/managers/timeline-manager/utils.svelte';
|
|
import type { VirtualScrollManager } from '$lib/managers/VirtualScrollManager/VirtualScrollManager.svelte';
|
|
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
|
import type { CommonPosition } from '$lib/utils/layout-utils';
|
|
import { fromTimelinePlainDate, getDateLocaleString } from '$lib/utils/timeline-util';
|
|
import { Icon } from '@immich/ui';
|
|
import { mdiCheckCircle, mdiCircleOutline } from '@mdi/js';
|
|
import type { Snippet } from 'svelte';
|
|
|
|
type Props = {
|
|
thumbnail: Snippet<
|
|
[
|
|
{
|
|
asset: TimelineAsset;
|
|
position: CommonPosition;
|
|
dayGroup: DayGroup;
|
|
groupIndex: number;
|
|
intersecting: boolean;
|
|
},
|
|
]
|
|
>;
|
|
customThumbnailLayout?: Snippet<[TimelineAsset]>;
|
|
singleSelect: boolean;
|
|
assetInteraction: AssetInteraction;
|
|
monthGroup: MonthGroup;
|
|
manager: VirtualScrollManager;
|
|
onDayGroupSelect: (dayGroup: DayGroup, assets: TimelineAsset[]) => void;
|
|
};
|
|
let {
|
|
thumbnail: thumbnailWithGroup,
|
|
customThumbnailLayout,
|
|
singleSelect,
|
|
assetInteraction,
|
|
monthGroup,
|
|
manager,
|
|
onDayGroupSelect,
|
|
}: Props = $props();
|
|
|
|
let { isUploading } = uploadAssetsStore;
|
|
let hoveredDayGroup = $state<string | null>(null);
|
|
|
|
const transitionDuration = $derived(monthGroup.timelineManager.suspendTransitions && !$isUploading ? 0 : 150);
|
|
|
|
const getDayGroupFullDate = (dayGroup: DayGroup): string => {
|
|
const { month, year } = dayGroup.monthGroup.yearMonth;
|
|
const date = fromTimelinePlainDate({
|
|
year,
|
|
month,
|
|
day: dayGroup.day,
|
|
});
|
|
return getDateLocaleString(date);
|
|
};
|
|
</script>
|
|
|
|
{#each filterRenderable(monthGroup.dayGroups) as dayGroup, groupIndex (dayGroup.day)}
|
|
{@const isDayGroupSelected = assetInteraction.selectedGroup.has(dayGroup.groupTitle)}
|
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
<section
|
|
class={[
|
|
{ 'transition-all': !monthGroup.timelineManager.suspendTransitions },
|
|
!monthGroup.timelineManager.suspendTransitions && `delay-${transitionDuration}`,
|
|
]}
|
|
data-group
|
|
style:position="absolute"
|
|
style:inset-inline-start={dayGroup.start + 'px'}
|
|
style:top={dayGroup.top + 'px'}
|
|
onmouseenter={() => (hoveredDayGroup = dayGroup.groupTitle)}
|
|
onmouseleave={() => (hoveredDayGroup = null)}
|
|
>
|
|
<!-- Day title -->
|
|
<div
|
|
class="flex pt-7 pb-5 max-md:pt-5 max-md:pb-3 h-6 place-items-center text-xs font-medium text-immich-fg dark:text-immich-dark-fg md:text-sm"
|
|
style:width={dayGroup.width + 'px'}
|
|
>
|
|
{#if !singleSelect}
|
|
<div
|
|
class="hover:cursor-pointer transition-all duration-200 ease-out overflow-hidden w-0"
|
|
class:w-8={hoveredDayGroup === dayGroup.groupTitle || assetInteraction.selectedGroup.has(dayGroup.groupTitle)}
|
|
onclick={() => onDayGroupSelect(dayGroup, assetsSnapshot(dayGroup.getAssets()))}
|
|
onkeydown={() => onDayGroupSelect(dayGroup, assetsSnapshot(dayGroup.getAssets()))}
|
|
>
|
|
{#if isDayGroupSelected}
|
|
<Icon icon={mdiCheckCircle} size="24" class="text-primary" />
|
|
{:else}
|
|
<Icon icon={mdiCircleOutline} size="24" class="text-light-500" />
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
|
|
<span class="w-full truncate first-letter:capitalize" title={getDayGroupFullDate(dayGroup)}>
|
|
{dayGroup.groupTitle}
|
|
</span>
|
|
</div>
|
|
|
|
<AssetLayout
|
|
{manager}
|
|
viewerAssets={dayGroup.viewerAssets}
|
|
height={dayGroup.height}
|
|
width={dayGroup.width}
|
|
{customThumbnailLayout}
|
|
>
|
|
{#snippet thumbnail({ asset, position, intersecting })}
|
|
{@render thumbnailWithGroup({ asset, position, dayGroup, groupIndex, intersecting })}
|
|
{/snippet}
|
|
</AssetLayout>
|
|
</section>
|
|
{/each}
|
|
|
|
<style>
|
|
section {
|
|
contain: layout paint style;
|
|
}
|
|
</style>
|