From 4a0045db445639bbcb99d6ab0b0b01126d8a9a3c Mon Sep 17 00:00:00 2001 From: Min Idzelis Date: Mon, 24 Mar 2025 17:36:36 -0400 Subject: [PATCH] feat(web): support long-press selection on mobile web (#16906) * feat(web): max grid row height responsive * also gallery-viewer * lint * feat(web): support long-press selection on mobile web * use svelte-gestures * fix test * Bug fix * globalThis * format * revert generator * Testing * bad merge * Fix typo/tap on thumbnail * feat: shrink header on small screens (#16909) * feat(web): shrink header on small screens * fix test * test * Fix test * Revert user-page-layout chagne * Restore icons sizes, make consistent, improve logo responsiveness * remove 4 more pix, lint * lint * chore --------- Co-authored-by: Alex Tran * Revert "Testing" This reverts commit 442f11c9e1538809f9208abcdff71a58b510ca98. --------- Co-authored-by: Alex Tran --- web/src/app.css | 1 + .../components/album-page/album-viewer.svelte | 8 +- .../thumbnail/__test__/thumbnail.spec.ts | 17 +++ .../assets/thumbnail/thumbnail.svelte | 34 ++++- .../lib/components/layouts/ErrorLayout.svelte | 2 +- .../layouts/user-page-layout.svelte | 2 +- .../onboarding-page/onboarding-hello.svelte | 2 +- .../photos-page/asset-date-group.svelte | 10 +- .../individual-shared-viewer.svelte | 5 +- .../drag-and-drop-upload-overlay.svelte | 2 +- .../immich-logo-small-link.svelte | 9 +- .../shared-components/immich-logo.svelte | 122 +++++++++++++++--- .../shared-components/modal-header.svelte | 2 +- .../navigation-bar/navigation-bar.svelte | 14 +- .../search-bar/search-bar.svelte | 2 +- .../side-bar/purchase-info.svelte | 4 +- .../side-bar/side-bar-section.svelte | 2 +- .../side-bar/supporter-badge.svelte | 2 +- web/src/lib/stores/mobile-device.svelte.ts | 4 + .../[[assetId=id]]/+page.svelte | 4 +- .../[[assetId=id]]/+page.svelte | 2 +- .../[[assetId=id]]/+page.svelte | 7 +- web/tailwind.config.js | 5 + 23 files changed, 201 insertions(+), 61 deletions(-) diff --git a/web/src/app.css b/web/src/app.css index a256cc9d802..4755f190299 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -70,6 +70,7 @@ font-family: 'Overpass', sans-serif; /* Used by layouts to ensure proper spacing between navbar and content */ --navbar-height: calc(theme(spacing.18) + 4px); + --navbar-height-md: calc(theme(spacing.18) + 4px - 14px); } :root.dark { diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index c1764025760..53040c8417f 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -29,7 +29,6 @@ let { sharedLink, user = undefined }: Props = $props(); const album = sharedLink.album as AlbumResponseDto; - let innerWidth: number = $state(0); let { isViewing: showAssetViewer } = assetViewingStore; @@ -56,7 +55,6 @@ } }, }} - bind:innerWidth />
@@ -74,7 +72,7 @@ {:else} {#snippet leading()} - + {/snippet} {#snippet trailing()} @@ -100,7 +98,9 @@ {/if}
-
+
diff --git a/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts b/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts index 62f0802a22b..3fbb8a550c5 100644 --- a/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts +++ b/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts @@ -3,6 +3,23 @@ import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte'; import { assetFactory } from '@test-data/factories/asset-factory'; import { fireEvent, render, screen } from '@testing-library/svelte'; +vi.hoisted(() => { + Object.defineProperty(globalThis, 'matchMedia', { + writable: true, + enumerable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); +}); + describe('Thumbnail component', () => { beforeAll(() => { vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock()); diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index 535f8e1408b..e4144a010de 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -1,4 +1,6 @@ - +

{$t('onboarding_welcome_user', { values: { user: $user.name } })}

diff --git a/web/src/lib/components/photos-page/asset-date-group.svelte b/web/src/lib/components/photos-page/asset-date-group.svelte index 3a9f6356b87..2e42a2bb770 100644 --- a/web/src/lib/components/photos-page/asset-date-group.svelte +++ b/web/src/lib/components/photos-page/asset-date-group.svelte @@ -136,7 +136,12 @@ -
+
{#each filterIntersecting(dateGroup.intersetingAssets) as intersectingAsset (intersectingAsset.id)} {@const position = intersectingAsset.position!} {@const asset = intersectingAsset.asset!} @@ -180,4 +185,7 @@ section { contain: layout paint style; } + [data-image-grid] { + user-select: none; + } diff --git a/web/src/lib/components/share-page/individual-shared-viewer.svelte b/web/src/lib/components/share-page/individual-shared-viewer.svelte index d5ff27ae8cf..b46342ad914 100644 --- a/web/src/lib/components/share-page/individual-shared-viewer.svelte +++ b/web/src/lib/components/share-page/individual-shared-viewer.svelte @@ -30,7 +30,6 @@ const viewport: Viewport = $state({ width: 0, height: 0 }); const assetInteraction = new AssetInteraction(); - let innerWidth: number = $state(0); let assets = $derived(sharedLink.assets); @@ -75,8 +74,6 @@ }; - -
{#if assetInteraction.selectionActive} goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}> {#snippet leading()} - + {/snippet} {#snippet trailing()} diff --git a/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte b/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte index 911abdbcec4..2ed5d684a4a 100644 --- a/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte +++ b/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte @@ -165,7 +165,7 @@ transition:fade={{ duration: 250 }} ondragover={onDragOver} > - +
{$t('drop_files_to_upload')}
{/if} diff --git a/web/src/lib/components/shared-components/immich-logo-small-link.svelte b/web/src/lib/components/shared-components/immich-logo-small-link.svelte index cd3149e6de1..7f96d88df81 100644 --- a/web/src/lib/components/shared-components/immich-logo-small-link.svelte +++ b/web/src/lib/components/shared-components/immich-logo-small-link.svelte @@ -1,13 +1,8 @@ - + diff --git a/web/src/lib/components/shared-components/immich-logo.svelte b/web/src/lib/components/shared-components/immich-logo.svelte index 308fc818130..4a96cfd6323 100644 --- a/web/src/lib/components/shared-components/immich-logo.svelte +++ b/web/src/lib/components/shared-components/immich-logo.svelte @@ -1,27 +1,115 @@ -{#if today.month === 4 && today.day === 1} - {$t('immich_logo')} -{:else} - {$t('immich_logo')} -{/if} + + {$t('immich_logo')} + {#if !noText} + + + + + + + + + {/if} + + + + + + + + + + diff --git a/web/src/lib/components/shared-components/modal-header.svelte b/web/src/lib/components/shared-components/modal-header.svelte index f2e4c960fa0..d7ec142012c 100644 --- a/web/src/lib/components/shared-components/modal-header.svelte +++ b/web/src/lib/components/shared-components/modal-header.svelte @@ -28,7 +28,7 @@
{#if showLogo} - + {:else if icon} {/if} diff --git a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte index b823e8fd569..02b55a1d07b 100644 --- a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte @@ -19,6 +19,7 @@ import ThemeButton from '../theme-button.svelte'; import UserAvatar from '../user-avatar.svelte'; import AccountInfoPanel from './account-info-panel.svelte'; + import { mobileDevice } from '$lib/stores/mobile-device.svelte'; interface Props { showUploadButton?: boolean; @@ -50,13 +51,16 @@ (shouldShowHelpPanel = false)} {info} /> {/if} -
+
- +
diff --git a/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte b/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte index 3d5e815996a..46fb031e20a 100644 --- a/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte +++ b/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte @@ -14,7 +14,7 @@ class="flex gap-1 mt-2 place-items-center dark:bg-immich-dark-primary/10 bg-gray-200/50 p-2 rounded-lg bg-clip-padding border border-transparent relative supporter-effect" class:place-content-center={centered} > - +

{$t('purchase_account_info')}

diff --git a/web/src/lib/stores/mobile-device.svelte.ts b/web/src/lib/stores/mobile-device.svelte.ts index f40e8aafdca..2d68c75d682 100644 --- a/web/src/lib/stores/mobile-device.svelte.ts +++ b/web/src/lib/stores/mobile-device.svelte.ts @@ -1,9 +1,13 @@ import { MediaQuery } from 'svelte/reactivity'; const hoverNone = new MediaQuery('hover: none'); +const maxMd = new MediaQuery('max-width: 767px'); export const mobileDevice = { get hoverNone() { return hoverNone.current; }, + get maxMd() { + return maxMd.current; + }, }; diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index ec148c91e7d..cbcb3ec7aca 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -603,7 +603,9 @@ {/if} {/if} -
+
{ diff --git a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 83dc40598aa..eba0d5ef32d 100644 --- a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -27,7 +27,6 @@ let { title, description } = $state(meta); let isOwned = $derived($user ? $user.id === sharedLink?.userId : false); let password = $state(''); - let innerWidth: number = $state(0); const handlePasswordSubmit = async () => { try { @@ -54,8 +53,6 @@ }; - - {title} @@ -64,7 +61,7 @@
{#snippet leading()} - + {/snippet} {#snippet trailing()} @@ -73,7 +70,7 @@
{$t('password_required')}
diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 2d81c28dd07..e701eefd7af 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -50,6 +50,11 @@ export default { }, screens: { tall: { raw: '(min-height: 800px)' }, + 'max-2xl': { max: '1535px' }, + 'max-xl': { max: '1279px' }, + 'max-lg': { max: '1023px' }, + 'max-md': { max: '767px' }, + 'max-sm': { max: '639px' }, }, }, },