mirror of
https://github.com/immich-app/immich.git
synced 2026-03-22 08:49:57 +03:00
* feat(web): adaptive progressive image loading for photo viewer Replace ImageManager with a new AdaptiveImageLoader that progressively loads images through quality tiers (thumbnail → preview → original). New components and utilities: - AdaptiveImage: layered image renderer with thumbhash, thumbnail, preview, and original layers with visibility managed by load state - AdaptiveImageLoader: state machine driving the quality progression with per-quality callbacks and error handling - ImageLayer/Image: low-level image elements with load/error lifecycle - PreloadManager: preloads adjacent assets for instant navigation - AlphaBackground/DelayedLoadingSpinner: loading state UI Zoom is handled via a derived CSS transform applied to the content wrapper in AdaptiveImage, with the zoom library (zoomTarget: null) only tracking state without manipulating the DOM directly. Also adds scaleToCover to container-utils and getAssetUrls to utils. * fix: don't partially render images in firefox * add passive loading indicator to asset-viewer --------- Co-authored-by: Alex <alex.tran1502@gmail.com>
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import { scaleToFit } from '$lib/utils/container-utils';
|
|
|
|
describe('scaleToFit', () => {
|
|
const tests = [
|
|
{
|
|
name: 'landscape image in square container',
|
|
dimensions: { width: 2000, height: 1000 },
|
|
container: { width: 500, height: 500 },
|
|
expected: { width: 500, height: 250 },
|
|
},
|
|
{
|
|
name: 'portrait image in square container',
|
|
dimensions: { width: 1000, height: 2000 },
|
|
container: { width: 500, height: 500 },
|
|
expected: { width: 250, height: 500 },
|
|
},
|
|
{
|
|
name: 'square image in square container',
|
|
dimensions: { width: 1000, height: 1000 },
|
|
container: { width: 500, height: 500 },
|
|
expected: { width: 500, height: 500 },
|
|
},
|
|
{
|
|
name: 'landscape image in landscape container',
|
|
dimensions: { width: 1600, height: 900 },
|
|
container: { width: 800, height: 600 },
|
|
expected: { width: 800, height: 450 },
|
|
},
|
|
{
|
|
name: 'portrait image in portrait container',
|
|
dimensions: { width: 900, height: 1600 },
|
|
container: { width: 600, height: 800 },
|
|
expected: { width: 450, height: 800 },
|
|
},
|
|
{
|
|
name: 'image matches container exactly',
|
|
dimensions: { width: 500, height: 300 },
|
|
container: { width: 500, height: 300 },
|
|
expected: { width: 500, height: 300 },
|
|
},
|
|
{
|
|
name: 'image smaller than container scales up',
|
|
dimensions: { width: 100, height: 50 },
|
|
container: { width: 400, height: 400 },
|
|
expected: { width: 400, height: 200 },
|
|
},
|
|
];
|
|
|
|
for (const { name, dimensions, container, expected } of tests) {
|
|
it(`should handle ${name}`, () => {
|
|
expect(scaleToFit(dimensions, container)).toEqual(expected);
|
|
});
|
|
}
|
|
});
|