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:
Min Idzelis
2026-04-03 13:27:12 -04:00
committed by GitHub
parent 207672c481
commit 649d14822a
16 changed files with 295 additions and 274 deletions
+8 -8
View File
@@ -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);
+49 -48
View File
@@ -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;