mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
refactor(web): rename MonthGroup to TimelineMonth (#27447)
Rename MonthGroup class to TimelineMonth to better convey that it represents a single month within the timeline. Updates the file, class, and all references across 16 files. Change-Id: Id50fd6d4b7d0e431571b67c0f81c0e316a6a6964
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import AssetLayout from '$lib/components/timeline/AssetLayout.svelte';
|
||||
import type { AssetMultiSelectManager } from '$lib/managers/asset-multi-select-manager.svelte';
|
||||
import { TimelineDay } from '$lib/managers/timeline-manager/timeline-day.svelte';
|
||||
import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte';
|
||||
import type { TimelineMonth } from '$lib/managers/timeline-manager/timeline-month.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { assetsSnapshot, filterIsInOrNearViewport } from '$lib/managers/timeline-manager/utils.svelte';
|
||||
import type { VirtualScrollManager } from '$lib/managers/VirtualScrollManager/VirtualScrollManager.svelte';
|
||||
@@ -27,7 +27,7 @@
|
||||
customThumbnailLayout?: Snippet<[TimelineAsset]>;
|
||||
singleSelect: boolean;
|
||||
assetInteraction: AssetMultiSelectManager;
|
||||
monthGroup: MonthGroup;
|
||||
timelineMonth: TimelineMonth;
|
||||
manager: VirtualScrollManager;
|
||||
onTimelineDaySelect: (timelineDay: TimelineDay, assets: TimelineAsset[]) => void;
|
||||
};
|
||||
@@ -36,7 +36,7 @@
|
||||
customThumbnailLayout,
|
||||
singleSelect,
|
||||
assetInteraction,
|
||||
monthGroup,
|
||||
timelineMonth,
|
||||
manager,
|
||||
onTimelineDaySelect,
|
||||
}: Props = $props();
|
||||
@@ -44,10 +44,10 @@
|
||||
let { isUploading } = uploadAssetsStore;
|
||||
let hoveredTimelineDay = $state<string | null>(null);
|
||||
|
||||
const transitionDuration = $derived(monthGroup.timelineManager.suspendTransitions && !$isUploading ? 0 : 150);
|
||||
const transitionDuration = $derived(timelineMonth.timelineManager.suspendTransitions && !$isUploading ? 0 : 150);
|
||||
|
||||
const getTimelineDayFullDate = (timelineDay: TimelineDay): string => {
|
||||
const { month, year } = timelineDay.monthGroup.yearMonth;
|
||||
const { month, year } = timelineDay.timelineMonth.yearMonth;
|
||||
const date = fromTimelinePlainDate({
|
||||
year,
|
||||
month,
|
||||
@@ -57,13 +57,13 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
{#each filterIsInOrNearViewport(monthGroup.timelineDays) as timelineDay, groupIndex (timelineDay.day)}
|
||||
{#each filterIsInOrNearViewport(timelineMonth.timelineDays) as timelineDay, groupIndex (timelineDay.day)}
|
||||
{@const isTimelineDaySelected = assetInteraction.selectedGroup.has(timelineDay.groupTitle)}
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<section
|
||||
class={[
|
||||
{ 'transition-all': !monthGroup.timelineManager.suspendTransitions },
|
||||
!monthGroup.timelineManager.suspendTransitions && `delay-${transitionDuration}`,
|
||||
{ 'transition-all': !timelineMonth.timelineManager.suspendTransitions },
|
||||
!timelineMonth.timelineManager.suspendTransitions && `delay-${transitionDuration}`,
|
||||
]}
|
||||
data-group
|
||||
style:position="absolute"
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
scrubberWidth = usingMobileDevice ? MOBILE_WIDTH : DESKTOP_WIDTH;
|
||||
});
|
||||
|
||||
const toScrollFromMonthGroupPercentage = (
|
||||
const toScrollFromTimelineMonthPercentage = (
|
||||
scrubberMonth: ViewportTopMonth,
|
||||
scrubberMonthPercent: number,
|
||||
scrubOverallPercent: number,
|
||||
@@ -125,7 +125,7 @@
|
||||
}
|
||||
};
|
||||
const scrollY = $derived(
|
||||
toScrollFromMonthGroupPercentage(viewportTopMonth, viewportTopMonthScrollPercent, timelineScrollPercent),
|
||||
toScrollFromTimelineMonthPercentage(viewportTopMonth, viewportTopMonthScrollPercent, timelineScrollPercent),
|
||||
);
|
||||
const timelineFullHeight = $derived(timelineManager.scrubberTimelineHeight);
|
||||
const relativeTopOffset = $derived(toScrollY(timelineTopOffset / timelineFullHeight));
|
||||
@@ -281,12 +281,12 @@
|
||||
const boundingClientRect = bestElement.boundingClientRect;
|
||||
const sy = boundingClientRect.y;
|
||||
const relativeY = y - sy;
|
||||
const monthGroupPercentY = relativeY / boundingClientRect.height;
|
||||
const timelineMonthPercentY = relativeY / boundingClientRect.height;
|
||||
return {
|
||||
isOnPaddingTop: false,
|
||||
isOnPaddingBottom: false,
|
||||
segment,
|
||||
monthGroupPercentY,
|
||||
timelineMonthPercentY,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@
|
||||
isOnPaddingTop,
|
||||
isOnPaddingBottom,
|
||||
segment: undefined,
|
||||
monthGroupPercentY: 0,
|
||||
timelineMonthPercentY: 0,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -328,7 +328,7 @@
|
||||
const upper = rect?.height - (PADDING_TOP + PADDING_BOTTOM);
|
||||
hoverY = clamp(clientY - rect?.top - PADDING_TOP, lower, upper);
|
||||
const x = rect!.left + rect!.width / 2;
|
||||
const { segment, monthGroupPercentY, isOnPaddingTop, isOnPaddingBottom } = getActive(x, clientY);
|
||||
const { segment, timelineMonthPercentY, isOnPaddingTop, isOnPaddingBottom } = getActive(x, clientY);
|
||||
activeSegment = segment;
|
||||
isHoverOnPaddingTop = isOnPaddingTop;
|
||||
isHoverOnPaddingBottom = isOnPaddingBottom;
|
||||
@@ -336,7 +336,7 @@
|
||||
const scrubData = {
|
||||
scrubberMonth: segmentDate,
|
||||
overallScrollPercent: toTimelineY(hoverY),
|
||||
scrubberMonthScrollPercent: monthGroupPercentY,
|
||||
scrubberMonthScrollPercent: timelineMonthPercentY,
|
||||
};
|
||||
if (wasDragging === false && isDragging) {
|
||||
void startScrub?.(scrubData);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
|
||||
import type { TimelineDay } from '$lib/managers/timeline-manager/timeline-day.svelte';
|
||||
import { isIntersecting } from '$lib/managers/timeline-manager/internal/intersection-support.svelte';
|
||||
import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte';
|
||||
import type { TimelineMonth } from '$lib/managers/timeline-manager/timeline-month.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset, TimelineManagerOptions, ViewportTopMonth } from '$lib/managers/timeline-manager/types';
|
||||
import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
||||
@@ -121,10 +121,11 @@
|
||||
timelineManager.scrollableElement = scrollableElement;
|
||||
});
|
||||
|
||||
const getAssetPosition = (assetId: string, monthGroup: MonthGroup) => monthGroup.findAssetAbsolutePosition(assetId);
|
||||
const getAssetPosition = (assetId: string, timelineMonth: TimelineMonth) =>
|
||||
timelineMonth.findAssetAbsolutePosition(assetId);
|
||||
|
||||
const scrollToAssetPosition = (assetId: string, monthGroup: MonthGroup) => {
|
||||
const position = getAssetPosition(assetId, monthGroup);
|
||||
const scrollToAssetPosition = (assetId: string, timelineMonth: TimelineMonth) => {
|
||||
const position = getAssetPosition(assetId, timelineMonth);
|
||||
|
||||
if (!position) {
|
||||
return;
|
||||
@@ -176,11 +177,11 @@
|
||||
// the performance benefits of deferred layouts while still supporting deep linking
|
||||
// to assets at the end of the timeline.
|
||||
timelineManager.isScrollingOnLoad = true;
|
||||
const monthGroup = await timelineManager.findMonthGroupForAsset({ id: assetId });
|
||||
if (!monthGroup) {
|
||||
const timelineMonth = await timelineManager.findTimelineMonthForAsset({ id: assetId });
|
||||
if (!timelineMonth) {
|
||||
return false;
|
||||
}
|
||||
scrollToAssetPosition(assetId, monthGroup);
|
||||
scrollToAssetPosition(assetId, timelineMonth);
|
||||
return true;
|
||||
} finally {
|
||||
timelineManager.isScrollingOnLoad = false;
|
||||
@@ -188,11 +189,11 @@
|
||||
};
|
||||
|
||||
const scrollToAsset = (asset: TimelineAsset) => {
|
||||
const monthGroup = timelineManager.getMonthGroupByAssetId(asset.id);
|
||||
if (!monthGroup) {
|
||||
const timelineMonth = timelineManager.getTimelineMonthByAssetId(asset.id);
|
||||
if (!timelineMonth) {
|
||||
return false;
|
||||
}
|
||||
scrollToAssetPosition(asset.id, monthGroup);
|
||||
scrollToAssetPosition(asset.id, timelineMonth);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -262,10 +263,10 @@
|
||||
}
|
||||
});
|
||||
|
||||
const scrollToSegmentPercentage = (segmentTop: number, segmentHeight: number, monthGroupScrollPercent: number) => {
|
||||
const scrollToSegmentPercentage = (segmentTop: number, segmentHeight: number, timelineMonthScrollPercent: number) => {
|
||||
const topOffset = segmentTop;
|
||||
const maxScrollPercent = timelineManager.maxScrollPercent;
|
||||
const delta = segmentHeight * monthGroupScrollPercent;
|
||||
const delta = segmentHeight * timelineMonthScrollPercent;
|
||||
const scrollToTop = (topOffset + delta) * maxScrollPercent;
|
||||
|
||||
timelineManager.scrollTo(scrollToTop);
|
||||
@@ -294,13 +295,13 @@
|
||||
scrubberMonthScrollPercent,
|
||||
);
|
||||
} else {
|
||||
const monthGroup = timelineManager.months.find(
|
||||
const timelineMonth = timelineManager.months.find(
|
||||
({ yearMonth: { year, month } }) => year === scrubberMonth.year && month === scrubberMonth.month,
|
||||
);
|
||||
if (!monthGroup) {
|
||||
if (!timelineMonth) {
|
||||
return;
|
||||
}
|
||||
scrollToSegmentPercentage(monthGroup.top, monthGroup.height, scrubberMonthScrollPercent);
|
||||
scrollToSegmentPercentage(timelineMonth.top, timelineMonth.height, scrubberMonthScrollPercent);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -325,28 +326,28 @@
|
||||
|
||||
const monthsLength = timelineManager.months.length;
|
||||
for (let i = -1; i < monthsLength + 1; i++) {
|
||||
let monthGroup: ViewportTopMonth;
|
||||
let monthGroupHeight: number;
|
||||
let timelineMonth: ViewportTopMonth;
|
||||
let timelineMonthHeight: number;
|
||||
if (i === -1) {
|
||||
// lead-in
|
||||
monthGroup = 'lead-in';
|
||||
monthGroupHeight = timelineManager.topSectionHeight;
|
||||
timelineMonth = 'lead-in';
|
||||
timelineMonthHeight = timelineManager.topSectionHeight;
|
||||
} else if (i === monthsLength) {
|
||||
// lead-out
|
||||
monthGroup = 'lead-out';
|
||||
monthGroupHeight = timelineManager.bottomSectionHeight;
|
||||
timelineMonth = 'lead-out';
|
||||
timelineMonthHeight = timelineManager.bottomSectionHeight;
|
||||
} else {
|
||||
monthGroup = timelineManager.months[i].yearMonth;
|
||||
monthGroupHeight = timelineManager.months[i].height;
|
||||
timelineMonth = timelineManager.months[i].yearMonth;
|
||||
timelineMonthHeight = timelineManager.months[i].height;
|
||||
}
|
||||
|
||||
let next = top - monthGroupHeight * maxScrollPercent;
|
||||
let next = top - timelineMonthHeight * maxScrollPercent;
|
||||
// instead of checking for < 0, add a little wiggle room for subpixel resolution
|
||||
if (next < -1 && monthGroup) {
|
||||
viewportTopMonth = monthGroup;
|
||||
if (next < -1 && timelineMonth) {
|
||||
viewportTopMonth = timelineMonth;
|
||||
|
||||
// allowing next to be at least 1 may cause percent to go negative, so ensure positive percentage
|
||||
viewportTopMonthScrollPercent = Math.max(0, top / (monthGroupHeight * maxScrollPercent));
|
||||
viewportTopMonthScrollPercent = Math.max(0, top / (timelineMonthHeight * maxScrollPercent));
|
||||
|
||||
// compensate for lost precision/rounding errors advance to the next bucket, if present
|
||||
if (viewportTopMonthScrollPercent > 0.9999 && i + 1 < monthsLength - 1) {
|
||||
@@ -432,16 +433,16 @@
|
||||
assetInteraction.clearCandidates();
|
||||
|
||||
if (assetInteraction.startAsset && rangeSelection) {
|
||||
const startBucket = timelineManager.getMonthGroupByAssetId(assetInteraction.startAsset.id);
|
||||
const endBucket = timelineManager.getMonthGroupByAssetId(asset.id);
|
||||
const startBucket = timelineManager.getTimelineMonthByAssetId(assetInteraction.startAsset.id);
|
||||
const endBucket = timelineManager.getTimelineMonthByAssetId(asset.id);
|
||||
|
||||
if (!startBucket || !endBucket) {
|
||||
return;
|
||||
}
|
||||
|
||||
const monthGroups = timelineManager.months;
|
||||
const startBucketIndex = monthGroups.indexOf(startBucket);
|
||||
const endBucketIndex = monthGroups.indexOf(endBucket);
|
||||
const timelineMonths = timelineManager.months;
|
||||
const startBucketIndex = timelineMonths.indexOf(startBucket);
|
||||
const endBucketIndex = timelineMonths.indexOf(endBucket);
|
||||
|
||||
if (startBucketIndex === -1 || endBucketIndex === -1) {
|
||||
return;
|
||||
@@ -452,9 +453,9 @@
|
||||
|
||||
// Select/deselect assets in range (start,end)
|
||||
for (let index = rangeStartIndex + 1; index < rangeEndIndex; index++) {
|
||||
const monthGroup = monthGroups[index];
|
||||
await timelineManager.loadMonthGroup(monthGroup.yearMonth);
|
||||
for (const monthAsset of monthGroup.assetsIterator()) {
|
||||
const timelineMonth = timelineMonths[index];
|
||||
await timelineManager.loadTimelineMonth(timelineMonth.yearMonth);
|
||||
for (const monthAsset of timelineMonth.assetsIterator()) {
|
||||
if (deselect) {
|
||||
assetInteraction.removeAssetFromMultiselectGroup(monthAsset.id);
|
||||
} else {
|
||||
@@ -465,10 +466,10 @@
|
||||
|
||||
// Update date group selection in range [start,end]
|
||||
for (let index = rangeStartIndex; index <= rangeEndIndex; index++) {
|
||||
const monthGroup = monthGroups[index];
|
||||
const timelineMonth = timelineMonths[index];
|
||||
|
||||
// Split month group into day groups and check each group
|
||||
for (const timelineDay of monthGroup.timelineDays) {
|
||||
for (const timelineDay of timelineMonth.timelineDays) {
|
||||
const timelineDayTitle = timelineDay.groupTitle;
|
||||
if (timelineDay.getAssets().every((a) => assetInteraction.hasSelectedAsset(a.id))) {
|
||||
assetInteraction.addGroupToMultiselectGroup(timelineDayTitle);
|
||||
@@ -517,7 +518,7 @@
|
||||
$effect(() => {
|
||||
if (assetViewerManager.asset && assetViewerManager.isViewing) {
|
||||
const { localDateTime } = getTimes(assetViewerManager.asset.fileCreatedAt, DateTime.local().offset / 60);
|
||||
void timelineManager.loadMonthGroup({ year: localDateTime.year, month: localDateTime.month });
|
||||
void timelineManager.loadTimelineMonth({ year: localDateTime.year, month: localDateTime.month });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -643,23 +644,23 @@
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
{#each timelineManager.months as monthGroup (monthGroup.viewId)}
|
||||
{@const isInOrNearViewport = monthGroup.isInOrNearViewport}
|
||||
{@const absoluteHeight = monthGroup.top}
|
||||
{#each timelineManager.months as timelineMonth (timelineMonth.viewId)}
|
||||
{@const isInOrNearViewport = timelineMonth.isInOrNearViewport}
|
||||
{@const absoluteHeight = timelineMonth.top}
|
||||
|
||||
{#if !monthGroup.isLoaded}
|
||||
{#if !timelineMonth.isLoaded}
|
||||
<div
|
||||
style:height={monthGroup.height + 'px'}
|
||||
style:height={timelineMonth.height + 'px'}
|
||||
style:position="absolute"
|
||||
style:transform={`translate3d(0,${absoluteHeight}px,0)`}
|
||||
style:width="100%"
|
||||
>
|
||||
<Skeleton {invisible} height={monthGroup.height} title={monthGroup.monthGroupTitle} />
|
||||
<Skeleton {invisible} height={timelineMonth.height} title={timelineMonth.title} />
|
||||
</div>
|
||||
{:else if isInOrNearViewport}
|
||||
<div
|
||||
class="month-group"
|
||||
style:height={monthGroup.height + 'px'}
|
||||
class="timeline-month"
|
||||
style:height={timelineMonth.height + 'px'}
|
||||
style:position="absolute"
|
||||
style:transform={`translate3d(0,${absoluteHeight}px,0)`}
|
||||
style:width="100%"
|
||||
@@ -668,7 +669,7 @@
|
||||
{assetInteraction}
|
||||
{customThumbnailLayout}
|
||||
{singleSelect}
|
||||
{monthGroup}
|
||||
{timelineMonth}
|
||||
manager={timelineManager}
|
||||
onTimelineDaySelect={handleGroupSelect}
|
||||
>
|
||||
@@ -735,7 +736,7 @@
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.month-group {
|
||||
.timeline-month {
|
||||
contain: layout size paint;
|
||||
transform-style: flat;
|
||||
backface-visibility: hidden;
|
||||
|
||||
Reference in New Issue
Block a user