From e9451f10d6d8ac78326414b58c449fd5a922b22f Mon Sep 17 00:00:00 2001 From: Mees Frensel <33722705+meesfrensel@users.noreply.github.com> Date: Thu, 5 Mar 2026 10:53:20 +0100 Subject: [PATCH 1/3] chore(web): small cleanup of timeline month (#26708) --- web/src/lib/components/timeline/Month.svelte | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/web/src/lib/components/timeline/Month.svelte b/web/src/lib/components/timeline/Month.svelte index 8a93dae63338e..91073a0a5f191 100644 --- a/web/src/lib/components/timeline/Month.svelte +++ b/web/src/lib/components/timeline/Month.svelte @@ -35,7 +35,6 @@ let { isUploading } = uploadAssetsStore; let hoveredDayGroup = $state(null); - const isMouseOverGroup = $derived(hoveredDayGroup !== null); const transitionDuration = $derived(monthGroup.timelineManager.suspendTransitions && !$isUploading ? 0 : 150); const filterIntersecting = (intersectables: T[]) => { @@ -68,7 +67,7 @@ onmouseenter={() => (hoveredDayGroup = dayGroup.groupTitle)} onmouseleave={() => (hoveredDayGroup = null)} > - +
onDayGroupSelect(dayGroup, assetsSnapshot(dayGroup.getAssets()))} onkeydown={() => onDayGroupSelect(dayGroup, assetsSnapshot(dayGroup.getAssets()))} > {#if isDayGroupSelected} {:else} - + {/if}
{/if} From 33d75462c9dfbd45b37b60571115ee75f96bb9dc Mon Sep 17 00:00:00 2001 From: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Date: Thu, 5 Mar 2026 10:58:26 +0100 Subject: [PATCH 2/3] fix(web): combobox dropdown positioning in modals (#26707) --- .../shared-components/combobox.svelte | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/web/src/lib/components/shared-components/combobox.svelte b/web/src/lib/components/shared-components/combobox.svelte index be1b73e1c5744..7230146886188 100644 --- a/web/src/lib/components/shared-components/combobox.svelte +++ b/web/src/lib/components/shared-components/combobox.svelte @@ -180,6 +180,17 @@ onSelect(selectedOption); }; + // TODO: move this combobox component into @immich/ui + // Bits UI dialogs use `contain: layout` so fixed descendants are positioned in dialog space + const getModalBounds = () => { + const modalRoot = input?.closest('[data-dialog-content]'); + if (!modalRoot || !getComputedStyle(modalRoot).contain.includes('layout')) { + return; + } + + return modalRoot.getBoundingClientRect(); + }; + const calculatePosition = (boundary: DOMRect | undefined) => { const visualViewport = window.visualViewport; @@ -187,29 +198,35 @@ return; } - const left = boundary.left + (visualViewport?.offsetLeft || 0); - const offsetTop = visualViewport?.offsetTop || 0; + const modalBounds = getModalBounds(); + const offsetTop = modalBounds?.top || 0; + const offsetLeft = modalBounds?.left || 0; + const rootHeight = modalBounds?.height || window.innerHeight; + + const top = boundary.top - offsetTop; + const bottom = boundary.bottom - offsetTop; + const left = boundary.left - offsetLeft; if (dropdownDirection === 'top') { return { - bottom: `${window.innerHeight - boundary.top - offsetTop}px`, + bottom: `${rootHeight - top}px`, left: `${left}px`, width: `${boundary.width}px`, - maxHeight: maxHeight(boundary.top - dropdownOffset), + maxHeight: maxHeight(top - dropdownOffset), }; } - const viewportHeight = visualViewport?.height || 0; - const availableHeight = viewportHeight - boundary.bottom; + const viewportHeight = visualViewport?.height || rootHeight; + const availableHeight = modalBounds ? rootHeight - bottom : viewportHeight - boundary.bottom; return { - top: `${boundary.bottom + offsetTop}px`, + top: `${bottom}px`, left: `${left}px`, width: `${boundary.width}px`, maxHeight: maxHeight(availableHeight - dropdownOffset), }; }; - const maxHeight = (size: number) => `min(${size}px,18rem)`; + const maxHeight = (size: number) => `min(${Math.max(size, 0)}px,18rem)`; const onPositionChange = () => { if (!isOpen) { From 78ba9cbc635fb4d2a7a12b1c334e5cec235ebcca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 10:59:51 +0100 Subject: [PATCH 3/3] chore(deps): update dependency multer to v2.1.1 [security] (#26705) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a026d30d90ebb..63ad290f7a197 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -504,7 +504,7 @@ importers: version: 0.40.3 multer: specifier: ^2.0.2 - version: 2.1.0 + version: 2.1.1 nest-commander: specifier: ^3.16.0 version: 3.20.1(@nestjs/common@11.1.14(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.14)(@types/inquirer@8.2.12)(@types/node@24.11.0)(typescript@5.9.3) @@ -9118,8 +9118,8 @@ packages: resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==} engines: {node: '>= 10.16.0'} - multer@2.1.0: - resolution: {integrity: sha512-TBm6j41rxNohqawsxlsWsNNh/VdV4QFXcBvRcPhXaA05EZ79z0qJ2bQFpync6JBoHTeNY5Q1JpG7AlTjdlfAEA==} + multer@2.1.1: + resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} engines: {node: '>= 10.16.0'} multicast-dns@7.2.5: @@ -22057,7 +22057,7 @@ snapshots: type-is: 1.6.18 xtend: 4.0.2 - multer@2.1.0: + multer@2.1.1: dependencies: append-field: 1.0.0 busboy: 1.6.0