refactor: rename mobileDevice to mediaQueryManager

This commit is contained in:
midzelis
2026-01-21 23:33:21 +00:00
parent 2f1d1edf10
commit 289ccfc7e0
11 changed files with 57 additions and 55 deletions

View File

@@ -13,7 +13,7 @@
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
import { handlePromiseError } from '$lib/utils';
import { cancelMultiselect } from '$lib/utils/asset-utils';
@@ -114,7 +114,7 @@
<ControlAppBar showBackButton={false}>
{#snippet leading()}
<a data-sveltekit-preload-data="hover" class="ms-4" href="/">
<Logo variant={mobileDevice.maxMd ? 'icon' : 'inline'} class="min-w-10" />
<Logo variant={mediaQueryManager.maxMd ? 'icon' : 'inline'} class="min-w-10" />
</a>
{/snippet}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { SCROLL_PROPERTIES } from '$lib/components/shared-components/album-selection/album-selection-utils';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { getAssetThumbnailUrl } from '$lib/utils';
import { normalizeSearchString } from '$lib/utils/string-utils.js';
import { type AlbumResponseDto } from '@immich/sdk';
@@ -54,7 +54,7 @@
onMultiSelect();
};
let usingMobileDevice = $derived(mobileDevice.pointerCoarse);
let usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
let mouseOver = $state(false);
const onMouseEnter = () => {
if (usingMobileDevice) {

View File

@@ -1,10 +1,18 @@
<script lang="ts">
import { thumbhash } from '$lib/actions/thumbhash';
import { ProjectionType } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { locale, playVideoThumbnailOnHover } from '$lib/stores/preferences.store';
import { getAssetOriginalUrl, getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
import { timeToSeconds } from '$lib/utils/date-time';
import { moveFocus } from '$lib/utils/focus-util';
import { currentUrlReplaceAssetId } from '$lib/utils/navigation';
import { getAltText } from '$lib/utils/thumbnail-util';
import { TUNABLES } from '$lib/utils/tunables';
import { AssetMediaSize, AssetVisibility, type UserResponseDto } from '@immich/sdk';
import { Icon } from '@immich/ui';
import {
mdiArchiveArrowDownOutline,
mdiCameraBurst,
@@ -15,21 +23,11 @@
mdiMotionPlayOutline,
mdiRotate360,
} from '@mdi/js';
import { thumbhash } from '$lib/actions/thumbhash';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { moveFocus } from '$lib/utils/focus-util';
import { currentUrlReplaceAssetId } from '$lib/utils/navigation';
import { TUNABLES } from '$lib/utils/tunables';
import { Icon } from '@immich/ui';
import { onMount } from 'svelte';
import type { ClassValue } from 'svelte/elements';
import { fade } from 'svelte/transition';
import ImageThumbnail from './image-thumbnail.svelte';
import VideoThumbnail from './video-thumbnail.svelte';
interface Props {
asset: TimelineAsset;
groupIndex?: number;
@@ -78,7 +76,7 @@
IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION },
} = TUNABLES;
let usingMobileDevice = $derived(mobileDevice.pointerCoarse);
let usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
let element: HTMLElement | undefined = $state();
let mouseOver = $state(false);
let loaded = $state(false);

View File

@@ -10,7 +10,7 @@
import { Route } from '$lib/route';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { handlePromiseError } from '$lib/utils';
import { cancelMultiselect, downloadArchive } from '$lib/utils/asset-utils';
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
@@ -110,7 +110,7 @@
<ControlAppBar onClose={() => goto(Route.photos())} backIcon={mdiArrowLeft} showBackButton={false}>
{#snippet leading()}
<a data-sveltekit-preload-data="hover" class="ms-4" href="/">
<Logo variant={mobileDevice.maxMd ? 'icon' : 'inline'} class="min-w-10" />
<Logo variant={mediaQueryManager.maxMd ? 'icon' : 'inline'} class="min-w-10" />
</a>
{/snippet}

View File

@@ -13,7 +13,7 @@
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { Route } from '$lib/route';
import { getGlobalActions } from '$lib/services/app.service';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { notificationManager } from '$lib/stores/notification-manager.svelte';
import { sidebarStore } from '$lib/stores/sidebar.svelte';
import { user } from '$lib/stores/user.store';
@@ -79,7 +79,7 @@
class="sidebar:hidden"
/>
<a data-sveltekit-preload-data="hover" href={Route.photos()}>
<Logo variant={mobileDevice.isFullSidebar ? 'inline' : 'icon'} class="max-md:h-12" />
<Logo variant={mediaQueryManager.isFullSidebar ? 'inline' : 'icon'} class="max-md:h-12" />
</a>
</div>
<div class="flex justify-between gap-4 lg:gap-8 pe-6">

View File

@@ -5,14 +5,14 @@ import { vi } from 'vitest';
const mocks = vi.hoisted(() => {
return {
mobileDevice: {
mediaQueryManager: {
isFullSidebar: false,
},
};
});
vi.mock('$lib/stores/mobile-device.svelte', () => ({
mobileDevice: mocks.mobileDevice,
vi.mock('$lib/stores/media-query-manager.svelte', () => ({
mediaQueryManager: mocks.mediaQueryManager,
}));
vi.mock('$lib/stores/sidebar.svelte', () => ({
@@ -25,7 +25,7 @@ vi.mock('$lib/stores/sidebar.svelte', () => ({
describe('Sidebar component', () => {
beforeEach(() => {
vi.resetAllMocks();
mocks.mobileDevice.isFullSidebar = false;
mocks.mediaQueryManager.isFullSidebar = false;
sidebarStore.isOpen = false;
});
@@ -39,7 +39,7 @@ describe('Sidebar component', () => {
'inert is $expectedInert when isFullSidebar=$isFullSidebar and isSidebarOpen=$isSidebarOpen',
({ isFullSidebar, isSidebarOpen, expectedInert }) => {
// setup
mocks.mobileDevice.isFullSidebar = isFullSidebar;
mocks.mediaQueryManager.isFullSidebar = isFullSidebar;
sidebarStore.isOpen = isSidebarOpen;
// when
@@ -53,7 +53,7 @@ describe('Sidebar component', () => {
it('should set width when sidebar is expanded', () => {
// setup
mocks.mobileDevice.isFullSidebar = false;
mocks.mediaQueryManager.isFullSidebar = false;
sidebarStore.isOpen = true;
// when
@@ -68,7 +68,7 @@ describe('Sidebar component', () => {
it('should close the sidebar if it is open on initial render', () => {
// setup
mocks.mobileDevice.isFullSidebar = false;
mocks.mediaQueryManager.isFullSidebar = false;
sidebarStore.isOpen = true;
// when

View File

@@ -2,7 +2,7 @@
import { clickOutside } from '$lib/actions/click-outside';
import { focusTrap } from '$lib/actions/focus-trap';
import { menuButtonId } from '$lib/components/shared-components/navigation-bar/navigation-bar.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { sidebarStore } from '$lib/stores/sidebar.svelte';
import { onMount, type Snippet } from 'svelte';
@@ -13,8 +13,8 @@
let { ariaLabel, children }: Props = $props();
const isHidden = $derived(!sidebarStore.isOpen && !mobileDevice.isFullSidebar);
const isExpanded = $derived(sidebarStore.isOpen && !mobileDevice.isFullSidebar);
const isHidden = $derived(!sidebarStore.isOpen && !mediaQueryManager.isFullSidebar);
const isExpanded = $derived(sidebarStore.isOpen && !mediaQueryManager.isFullSidebar);
onMount(() => {
closeSidebar();

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { ScrubberMonth, ViewportTopMonth } from '$lib/managers/timeline-manager/types';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { getTabbable } from '$lib/utils/focus-util';
import { type ScrubberListener } from '$lib/utils/timeline-util';
import { Icon } from '@immich/ui';
@@ -65,7 +65,7 @@
const toScrollY = (percent: number) => percent * (height - (PADDING_TOP + PADDING_BOTTOM));
const toTimelineY = (scrollY: number) => scrollY / (height - (PADDING_TOP + PADDING_BOTTOM));
const usingMobileDevice = $derived(mobileDevice.pointerCoarse);
const usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
const MOBILE_WIDTH = 20;
const DESKTOP_WIDTH = 60;

View File

@@ -21,7 +21,7 @@
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
import { isAssetViewerRoute, navigate } from '$lib/utils/navigation';
import { getTimes, type ScrubberListener } from '$lib/utils/timeline-util';
import { type AlbumResponseDto, type PersonResponseDto, type UserResponseDto } from '@immich/sdk';
@@ -106,8 +106,8 @@
let scrubberWidth = $state(0);
const isEmpty = $derived(timelineManager.isInitialized && timelineManager.months.length === 0);
const maxMd = $derived(mobileDevice.maxMd);
const usingMobileDevice = $derived(mobileDevice.pointerCoarse);
const maxMd = $derived(mediaQueryManager.maxMd);
const usingMobileDevice = $derived(mediaQueryManager.pointerCoarse);
$effect(() => {
const layoutOptions = maxMd

View File

@@ -1,17 +1,21 @@
import { MediaQuery } from 'svelte/reactivity';
const pointerCoarse = new MediaQuery('pointer:coarse');
const maxMd = new MediaQuery('max-width: 767px');
const sidebar = new MediaQuery(`min-width: 850px`);
export const mobileDevice = {
get pointerCoarse() {
return pointerCoarse.current;
},
get maxMd() {
return maxMd.current;
},
get isFullSidebar() {
return sidebar.current;
},
};
import { MediaQuery } from 'svelte/reactivity';
const pointerCoarse = new MediaQuery('pointer:coarse');
const maxMd = new MediaQuery('max-width: 767px');
const sidebar = new MediaQuery(`min-width: 850px`);
const reducedMotion = new MediaQuery('prefers-reduced-motion: reduce');
export const mediaQueryManager = {
get pointerCoarse() {
return pointerCoarse.current;
},
get maxMd() {
return maxMd.current;
},
get isFullSidebar() {
return sidebar.current;
},
get reducedMotion() {
return reducedMotion.current;
},
};

View File

@@ -1,20 +1,20 @@
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
class SidebarStore {
isOpen = $derived.by(() => mobileDevice.isFullSidebar);
isOpen = $derived.by(() => mediaQueryManager.isFullSidebar);
/**
* Reset the sidebar visibility to the default, based on the current screen width.
*/
reset() {
this.isOpen = mobileDevice.isFullSidebar;
this.isOpen = mediaQueryManager.isFullSidebar;
}
/**
* Toggles the sidebar visibility, if available at the current screen width.
*/
toggle() {
this.isOpen = mobileDevice.isFullSidebar ? true : !this.isOpen;
this.isOpen = mediaQueryManager.isFullSidebar ? true : !this.isOpen;
}
}