0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-04-08 03:01:32 -05:00

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 <alex.tran1502@gmail.com>

* Revert "Testing"

This reverts commit 442f11c9e1.

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
Min Idzelis 2025-03-24 17:36:36 -04:00 committed by GitHub
parent a651a4bf0e
commit 4a0045db44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 201 additions and 61 deletions

View file

@ -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 {

View file

@ -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
/>
<header>
@ -74,7 +72,7 @@
{:else}
<ControlAppBar showBackButton={false}>
{#snippet leading()}
<ImmichLogoSmallLink width={innerWidth} />
<ImmichLogoSmallLink />
{/snippet}
{#snippet trailing()}
@ -100,7 +98,9 @@
{/if}
</header>
<main class="relative h-screen overflow-hidden bg-immich-bg px-6 pt-[var(--navbar-height)] dark:bg-immich-dark-bg">
<main
class="relative h-screen overflow-hidden bg-immich-bg px-6 max-md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)] dark:bg-immich-dark-bg"
>
<AssetGrid enableRouting={true} {album} {assetStore} {assetInteraction}>
<section class="pt-8 md:pt-24">
<!-- ALBUM TITLE -->

View file

@ -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());

View file

@ -1,4 +1,6 @@
<script lang="ts">
import { press, tap } from 'svelte-gestures';
import Icon from '$lib/components/elements/icon.svelte';
import { ProjectionType } from '$lib/constants';
import { getAssetThumbnailUrl, isSharedLink } from '$lib/utils';
@ -23,6 +25,7 @@
import { currentUrlReplaceAssetId } from '$lib/utils/navigation';
import { TUNABLES } from '$lib/utils/tunables';
import { thumbhash } from '$lib/actions/thumbhash';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
interface Props {
asset: AssetResponseDto;
@ -71,6 +74,7 @@
IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION },
} = TUNABLES;
let isTouchDevice = $derived(mobileDevice.hoverNone);
let focussableElement: HTMLElement | undefined = $state();
let mouseOver = $state(false);
let loaded = $state(false);
@ -100,6 +104,9 @@
onClick?.($state.snapshot(asset));
};
const handleClick = (e: MouseEvent) => {
if (isTouchDevice) {
return;
}
if (e.ctrlKey || e.metaKey) {
return;
}
@ -109,6 +116,9 @@
};
const onMouseEnter = () => {
if (isTouchDevice) {
return;
}
mouseOver = true;
onMouseEvent?.({ isMouseOver: true, selectedGroupIndex: groupIndex });
};
@ -138,6 +148,13 @@
<!-- svelte queries for all links on afterNavigate, leading to performance problems in asset-grid which updates
the navigation url on scroll. Replace this with button for now. -->
<!-- as of iOS17, there is a preference for long press speed, which is not available for mobile web.
The defaults are as follows:
fast: 200ms
default: 500ms
slow: ??ms
-->
<div
class="group"
style:width="{width}px"
@ -146,6 +163,10 @@
class:cursor-pointer={!disabled}
onmouseenter={onMouseEnter}
onmouseleave={onMouseLeave}
use:press={() => ({ timeframe: 350, triggerBeforeFinished: true })}
use:tap={() => ({ timeframe: 350 })}
onpress={(evt) => (evt.detail.pointerType === 'mouse' ? void 0 : onSelect?.($state.snapshot(asset)))}
ontap={(evt) => (evt.detail.pointerType === 'mouse' ? void 0 : callClickHandlers())}
onkeydown={(evt) => {
if (evt.key === 'Enter') {
callClickHandlers();
@ -161,7 +182,7 @@
onfocus={handleFocus}
data-testid="container-with-tabindex"
>
{#if mouseOver && !disableMouseOver}
{#if !isTouchDevice && mouseOver && !disableMouseOver}
<!-- lazy show the url on mouse over-->
<a
class="absolute z-30 {className} top-[41px]"
@ -208,11 +229,12 @@
class:rounded-xl={selected}
>
<!-- Gradient overlay on hover -->
<div
class="absolute z-10 h-full w-full bg-gradient-to-b from-black/25 via-[transparent_25%] opacity-0 transition-opacity group-hover:opacity-100"
class:rounded-xl={selected}
></div>
{#if !isTouchDevice}
<div
class="absolute z-10 h-full w-full bg-gradient-to-b from-black/25 via-[transparent_25%] opacity-0 transition-opacity group-hover:opacity-100"
class:rounded-xl={selected}
></div>
{/if}
<!-- Outline on focus -->
<div
class="absolute size-full group-focus-visible:outline outline-4 -outline-offset-4 outline-immich-primary"

View file

@ -25,7 +25,7 @@
<section class="bg-immich-bg dark:bg-immich-dark-bg">
<div class="flex place-items-center border-b px-6 py-4 dark:border-b-immich-dark-gray">
<a class="flex place-items-center gap-2 hover:cursor-pointer" href="/photos">
<ImmichLogo width="55%" />
<ImmichLogo class="h-[50px]" />
</a>
</div>
</section>

View file

@ -51,7 +51,7 @@
</header>
<main
tabindex="-1"
class="relative grid h-screen grid-cols-[theme(spacing.18)_auto] overflow-hidden bg-immich-bg pt-[var(--navbar-height)] dark:bg-immich-dark-bg md:grid-cols-[theme(spacing.64)_auto]"
class="relative grid h-screen grid-cols-[theme(spacing.18)_auto] overflow-hidden bg-immich-bg max-md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)] dark:bg-immich-dark-bg md:grid-cols-[theme(spacing.64)_auto]"
>
{#if sidebar}{@render sidebar()}{:else if admin}
<AdminSideBar />

View file

@ -15,7 +15,7 @@
</script>
<OnboardingCard>
<ImmichLogo noText width="75" />
<ImmichLogo noText class="h-[50px]" />
<p class="font-medium text-6xl my-6 text-immich-primary dark:text-immich-dark-primary">
{$t('onboarding_welcome_user', { values: { user: $user.name } })}
</p>

View file

@ -136,7 +136,12 @@
</div>
<!-- Image grid -->
<div class="relative overflow-clip" style:height={dateGroup.height + 'px'} style:width={dateGroup.width + 'px'}>
<div
data-image-grid
class="relative overflow-clip"
style:height={dateGroup.height + 'px'}
style:width={dateGroup.width + 'px'}
>
{#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;
}
</style>

View file

@ -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 @@
};
</script>
<svelte:window bind:innerWidth />
<section class="bg-immich-bg dark:bg-immich-dark-bg">
{#if assetInteraction.selectionActive}
<AssetSelectControlBar
@ -94,7 +91,7 @@
{:else}
<ControlAppBar onClose={() => goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}>
{#snippet leading()}
<ImmichLogoSmallLink width={innerWidth} />
<ImmichLogoSmallLink />
{/snippet}
{#snippet trailing()}

View file

@ -165,7 +165,7 @@
transition:fade={{ duration: 250 }}
ondragover={onDragOver}
>
<ImmichLogo noText class="m-16 w-48 animate-bounce" />
<ImmichLogo noText class="m-16 h-48 animate-bounce" />
<div class="text-2xl">{$t('drop_files_to_upload')}</div>
</div>
{/if}

View file

@ -1,13 +1,8 @@
<script lang="ts">
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
interface Props {
width: number;
}
let { width }: Props = $props();
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
</script>
<a data-sveltekit-preload-data="hover" class="ml-4" href="/">
<ImmichLogo class="h-[24px] w-[24px] max-w-none md:w-auto md:h-10 md:max-w-full" noText={width < 768} />
<ImmichLogo class="h-[50px] max-w-none md:w-auto md:max-w-full" noText={mobileDevice.maxMd} />
</a>

View file

@ -1,27 +1,115 @@
<script lang="ts">
import { Theme } from '$lib/constants';
import { colorTheme } from '$lib/stores/preferences.store';
import { immichLogo, immichLogoInlineDark, immichLogoInlineLight, immichLogoJson } from '@immich/ui';
import { DateTime } from 'luxon';
import { t } from 'svelte-i18n';
import type { HTMLImgAttributes } from 'svelte/elements';
interface Props extends HTMLImgAttributes {
noText?: boolean;
draggable?: boolean;
class?: string | undefined;
}
let { noText = false, draggable = false, ...rest }: Props = $props();
const logoUrl = $derived(
noText ? immichLogo : $colorTheme.value == Theme.LIGHT ? immichLogoInlineLight : immichLogoInlineDark,
);
const today = DateTime.now().toLocal();
let { noText = false, class: cssClass }: Props = $props();
const viewBox = $derived(`0 0 ${noText ? '260' : '792'} 266.25`);
</script>
{#if today.month === 4 && today.day === 1}
<img src="data:image/png;base64, {immichLogoJson.content}" alt={$t('immich_logo')} class="h-14" {draggable} />
{:else}
<img src={logoUrl} alt={$t('immich_logo')} {draggable} {...rest} />
{/if}
<svg {viewBox} class={cssClass}>
<title>{$t('immich_logo')}</title>
{#if !noText}
<g class="st0 dark:fill-[#accbfa]">
<path
d="M268.73,63.18c6.34,0,11.52,5.18,11.52,11.35c0,6.34-5.18,11.35-11.52,11.35s-11.69-5.01-11.69-11.35
C257.04,68.36,262.39,63.18,268.73,63.18z M258.88,122.45c0-3.01-0.67-7.85-0.67-10.68c0-6.01,4.67-10.68,10.52-10.68
c5.84,0,10.52,4.67,10.52,10.68c0,2.84-0.83,7.68-0.83,10.68v38.73c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.67,10.68-10.52,10.68
c-5.84,0-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68V122.45z"
/>
<path
d="M394.28,171.87c0-2.84,0.83-7.68,0.83-10.68V132.3c0-10.18-5.34-16.86-14.52-16.86c-6.01,0-11.35,3-14.86,8.85
c0.33,1.84,0.5,3.67,0.5,5.68v31.22c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.67,10.68-10.68,10.68c-5.51,0-10.35-4.67-10.35-10.68
c0-2.84,0.83-7.68,0.83-10.68V131.8c0-3.17-0.5-6.01-1.67-8.51c-2.17-4.84-6.51-7.85-12.52-7.85c-6.18,0-11.19,3.17-14.86,8.85
v36.9c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.84,10.68-10.52,10.68c-5.84,0-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68
v-38.57c0-3.01-1.5-8.35-1.5-10.85c0-6.01,4.34-10.68,10.18-10.68c5.51,0,8.68,3.67,9.68,8.51c5.01-6.68,12.02-10.85,21.2-10.85
c10.85,0,18.7,5.18,23.54,13.52c5.51-8.68,13.52-13.52,23.54-13.52c16.86,0,29.72,12.19,29.72,31.72v30.72
c0,3.01,0.67,7.85,0.67,10.68c0,6.01-4.51,10.68-10.52,10.68C399.12,182.55,394.28,177.88,394.28,171.87z"
/>
<path
d="M528.5,171.87c0-2.84,0.83-7.68,0.83-10.68V132.3c0-10.18-5.34-16.86-14.52-16.86c-6.01,0-11.35,3-14.86,8.85
c0.33,1.84,0.5,3.67,0.5,5.68v31.22c0,3.01,0.84,7.85,0.84,10.68c0,6.01-4.67,10.68-10.68,10.68c-5.51,0-10.35-4.67-10.35-10.68
c0-2.84,0.84-7.68,0.84-10.68V131.8c0-3.17-0.5-6.01-1.67-8.51c-2.17-4.84-6.51-7.85-12.52-7.85c-6.18,0-11.19,3.17-14.86,8.85
v36.9c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.84,10.68-10.52,10.68c-5.84,0-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68
v-38.57c0-3.01-1.5-8.35-1.5-10.85c0-6.01,4.34-10.68,10.18-10.68c5.51,0,8.68,3.67,9.68,8.51c5.01-6.68,12.02-10.85,21.2-10.85
c10.85,0,18.7,5.18,23.54,13.52c5.51-8.68,13.52-13.52,23.54-13.52c16.86,0,29.72,12.19,29.72,31.72v30.72
c0,3.01,0.67,7.85,0.67,10.68c0,6.01-4.51,10.68-10.52,10.68C533.35,182.55,528.5,177.88,528.5,171.87z"
/>
<path
d="M576.92,63.18c6.34,0,11.52,5.18,11.52,11.35c0,6.34-5.18,11.35-11.52,11.35s-11.69-5.01-11.69-11.35
C565.23,68.36,570.57,63.18,576.92,63.18z M567.07,122.45c0-3.01-0.67-7.85-0.67-10.68c0-6.01,4.67-10.68,10.52-10.68
s10.52,4.67,10.52,10.68c0,2.84-0.84,7.68-0.84,10.68v38.73c0,3.01,0.84,7.85,0.84,10.68c0,6.01-4.67,10.68-10.52,10.68
s-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68V122.45z"
/>
<path
d="M601.79,141.31c0-23.54,14.69-42.57,39.07-42.57c12.86,0,24.71,5.84,30.05,14.53c2,3.17,2.34,5.01,2.34,6.51
c0,5.18-4.01,9.52-9.85,9.52c-3.84,0-7.34-2.17-8.85-6.01c-2.34-5.18-6.85-8.18-13.69-8.18c-12.86,0-20.03,11.52-20.03,26.04
c0,14.69,7.51,26.04,20.53,26.04c7.01,0,12.02-2.5,14.36-7.68c1.67-3.51,4.84-6.51,9.18-6.51c6.01,0,9.68,4.17,9.68,9.35
c0,2.5-1,5.51-3.17,8.35c-5.51,7.35-15.86,13.19-30.05,13.19C616.32,183.89,601.79,165.19,601.79,141.31z"
/>
<path
d="M737.69,171.87c0-2.84,0.67-7.68,0.67-10.68v-28.55c0-10.18-5.68-17.2-15.36-17.2
c-6.68,0-12.35,3.17-16.03,8.35v37.4c0,3.01,0.67,7.85,0.67,10.68c0,6.01-4.67,10.68-10.52,10.68s-10.52-4.67-10.52-10.68
c0-2.84,0.84-7.68,0.84-10.68v-80.8c0-3.01-0.84-7.85-0.84-10.68c0-6.01,4.84-10.68,10.52-10.68c5.84,0,10.52,4.67,10.52,10.68
c0,2.84-0.67,7.68-0.67,10.68v27.21c5.01-5.51,12.19-8.85,21.37-8.85c17.2,0,29.55,12.86,29.55,31.22v31.22
c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.84,10.68-10.52,10.68C742.36,182.55,737.69,177.88,737.69,171.87z"
/>
</g>
{/if}
<g>
<path
class="st1"
d="M114.82,96.21c11.92,10.55,21.52,21.86,27.7,32.52c10.62-18.99,17.71-41.55,17.8-55.92c0-0.1,0-0.19,0-0.28
c0-21.26-21.21-29.54-39.48-29.54s-39.48,8.28-39.48,29.54c0,0.29,0,0.68,0,1.15C91.54,78.2,103.61,86.29,114.82,96.21z"
/>
<path
class="st2"
d="M49.8,154.19c7.45-8.29,18.88-17.27,31.77-24.86c13.72-8.07,27.44-13.71,39.49-16.3
c-14.78-15.96-34.04-29.68-47.68-34.21c-0.1-0.03-0.18-0.06-0.27-0.09c-20.22-6.57-34.65,11.05-40.3,28.42s-4.33,40.11,15.89,46.68
C48.99,153.93,49.35,154.05,49.8,154.19z"
/>
<path
class="st3"
d="M209.07,106.86c-5.65-17.38-20.07-34.99-40.3-28.42c-0.28,0.09-0.65,0.21-1.09,0.35
c-1.16,11.08-5.12,25.07-11.09,38.79c-6.35,14.6-14.14,27.23-22.36,36.39c21.34,4.23,44.99,4,58.68-0.35
c0.1-0.03,0.19-0.06,0.27-0.09C213.4,146.97,214.71,124.24,209.07,106.86z"
/>
<path
class="st4"
d="M102.8,171.18c-3.44-15.54-4.56-30.34-3.3-42.59c-19.75,9.12-38.75,23.2-47.27,34.78
c-0.06,0.08-0.11,0.16-0.16,0.23c-12.5,17.2-0.2,36.37,14.58,47.11s36.81,16.51,49.31-0.69c0.17-0.24,0.4-0.55,0.68-0.93
C111.05,199.44,106.04,185.79,102.8,171.18z"
/>
<path
class="st5"
d="M189.48,162.49c-10.9,2.33-25.42,2.88-40.32,1.44c-15.84-1.53-30.26-5.03-41.52-10.02
c2.57,21.6,10.09,44.02,18.47,55.7c0.06,0.08,0.11,0.16,0.16,0.23c12.5,17.2,34.52,11.43,49.31,0.69
c14.78-10.74,27.08-29.9,14.58-47.11C189.99,163.18,189.76,162.86,189.48,162.49z"
/>
</g>
</svg>
<style>
.st0 {
fill: #4251b0;
}
.st1 {
fill: #fa2921;
}
.st2 {
fill: #ed79b5;
}
.st3 {
fill: #ffb400;
}
.st4 {
fill: #1e83f7;
}
.st5 {
fill: #18c249;
}
</style>

View file

@ -28,7 +28,7 @@
<div class="flex place-items-center justify-between px-5 pb-3">
<div class="flex gap-2 place-items-center">
{#if showLogo}
<ImmichLogo noText={true} width={32} />
<ImmichLogo noText={true} class="h-[40px]" />
{:else if icon}
<Icon path={icon} size={24} ariaHidden={true} class="text-immich-primary dark:text-immich-dark-primary" />
{/if}

View file

@ -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 @@
<HelpAndFeedbackModal onClose={() => (shouldShowHelpPanel = false)} {info} />
{/if}
<section id="dashboard-navbar" class="fixed z-[900] h-[var(--navbar-height)] w-screen text-sm">
<section
id="dashboard-navbar"
class="fixed z-[900] max-md:h-[var(--navbar-height-md)] h-[var(--navbar-height)] w-screen text-sm"
>
<SkipLink text={$t('skip_to_content')} />
<div
class="grid h-full grid-cols-[theme(spacing.18)_auto] items-center border-b bg-immich-bg py-2 dark:border-b-immich-dark-gray dark:bg-immich-dark-bg md:grid-cols-[theme(spacing.64)_auto]"
>
<a data-sveltekit-preload-data="hover" class="ml-4" href={AppRoute.PHOTOS}>
<ImmichLogo width="55%" noText={innerWidth < 768} />
<ImmichLogo class="max-md:h-[48px] h-[50px]" noText={mobileDevice.maxMd} />
</a>
<div class="flex justify-between gap-4 lg:gap-8 pr-6">
<div class="hidden w-full max-w-5xl flex-1 tall:pl-0 sm:block">
@ -71,7 +75,7 @@
color="secondary"
shape="round"
variant="ghost"
size="large"
size="medium"
icon={mdiMagnify}
href={AppRoute.SEARCH}
id="search-button"
@ -95,7 +99,7 @@
color="secondary"
shape="round"
variant="ghost"
size="large"
size="medium"
onclick={onUploadClick}
title={$t('upload')}
aria-label={$t('upload')}
@ -115,7 +119,7 @@
shape="round"
color="secondary"
variant="ghost"
size="large"
size="medium"
title={$t('support_and_feedback')}
icon={mdiHelpCircleOutline}
onclick={() => (shouldShowHelpPanel = !shouldShowHelpPanel)}

View file

@ -209,7 +209,7 @@
type="text"
name="q"
id="main-search-bar"
class="w-full transition-all border-2 px-14 py-4 text-immich-fg/75 dark:text-immich-dark-fg
class="w-full transition-all border-2 px-14 py-4 max-md:py-2 text-immich-fg/75 dark:text-immich-dark-fg
{grayTheme ? 'dark:bg-immich-dark-gray' : 'dark:bg-immich-dark-bg'}
{showSuggestions && isSearchSuggestions ? 'rounded-t-3xl' : 'rounded-3xl bg-gray-200'}
{$isSearchEnabled && !showFilter ? 'border-gray-200 dark:border-gray-700 bg-white' : 'border-transparent'}"

View file

@ -100,7 +100,7 @@
<div class="flex justify-between w-full place-items-center place-content-center">
<div class="flex place-items-center place-content-center gap-1">
<div class="h-6 w-6">
<ImmichLogo noText />
<ImmichLogo noText class="h-[24px]" />
</div>
<p class="flex text-immich-primary dark:text-immich-dark-primary font-medium">
{$t('purchase_button_buy_immich')}
@ -132,7 +132,7 @@
>
<div class="flex justify-between place-items-center">
<div class="h-10 w-10">
<ImmichLogo noText />
<ImmichLogo noText class="h-[32px]" />
</div>
<CircleIconButton
icon={mdiClose}

View file

@ -11,7 +11,7 @@
<section
id="sidebar"
tabindex="-1"
class="immich-scrollbar group relative z-10 flex w-18 flex-col gap-1 overflow-y-auto bg-immich-bg pt-8 transition-all duration-200 dark:bg-immich-dark-bg hover:sm:w-64 hover:sm:border-r hover:sm:pr-6 hover:sm:shadow-2xl hover:sm:dark:border-r-immich-dark-gray md:w-64 md:pr-6 hover:md:border-none hover:md:shadow-none"
class="immich-scrollbar group relative z-10 flex w-18 flex-col gap-1 overflow-y-auto bg-immich-bg pt-8 max-md:pt-16 transition-all duration-200 dark:bg-immich-dark-bg hover:sm:w-64 hover:sm:border-r hover:sm:pr-6 hover:sm:shadow-2xl hover:sm:dark:border-r-immich-dark-gray md:w-64 md:pr-6 hover:md:border-none hover:md:shadow-none"
>
{@render children?.()}
</section>

View file

@ -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}
>
<ImmichLogo class={logoSize === 'sm' ? 'size-6' : 'size-8'} noText />
<ImmichLogo class={logoSize === 'sm' ? 'h-6' : 'h-8'} noText />
<p class="dark:text-gray-100">{$t('purchase_account_info')}</p>
</div>

View file

@ -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;
},
};

View file

@ -603,7 +603,9 @@
{/if}
{/if}
<main class="relative h-screen overflow-hidden bg-immich-bg px-6 pt-[var(--navbar-height)] dark:bg-immich-dark-bg">
<main
class="relative h-screen overflow-hidden bg-immich-bg px-6 max-md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)] dark:bg-immich-dark-bg"
>
<AssetGrid
enableRouting={viewMode === AlbumPageViewMode.SELECT_ASSETS ? false : true}
{album}

View file

@ -486,7 +486,7 @@
</header>
<main
class="relative h-screen overflow-hidden bg-immich-bg tall:ml-4 pt-[var(--navbar-height)] dark:bg-immich-dark-bg"
class="relative h-screen overflow-hidden bg-immich-bg tall:ml-4 md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)] dark:bg-immich-dark-bg"
use:scrollMemoryClearer={{
routeStartsWith: AppRoute.PEOPLE,
beforeClear: () => {

View file

@ -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 @@
};
</script>
<svelte:window bind:innerWidth />
<svelte:head>
<title>{title}</title>
<meta name="description" content={description} />
@ -64,7 +61,7 @@
<header>
<ControlAppBar showBackButton={false}>
{#snippet leading()}
<ImmichLogoSmallLink width={innerWidth} />
<ImmichLogoSmallLink />
{/snippet}
{#snippet trailing()}
@ -73,7 +70,7 @@
</ControlAppBar>
</header>
<main
class="relative h-screen overflow-hidden bg-immich-bg px-6 pt-[var(--navbar-height)] dark:bg-immich-dark-bg sm:px-12 md:px-24 lg:px-40"
class="relative h-screen overflow-hidden bg-immich-bg px-6 max-md:pt-[var(--navbar-height-md)] pt-[var(--navbar-height)] dark:bg-immich-dark-bg sm:px-12 md:px-24 lg:px-40"
>
<div class="flex flex-col items-center justify-center mt-20">
<div class="text-2xl font-bold text-immich-primary dark:text-immich-dark-primary">{$t('password_required')}</div>

View file

@ -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' },
},
},
},