immich-app / immich

High performance self-hosted photo and video management solution.
https://immich.app
GNU Affero General Public License v3.0
52.89k stars 2.81k forks source link

[BUG] Scrolling not possible outside of asset-grid #3878

Closed fabiannagel closed 2 months ago

fabiannagel commented 1 year ago

The bug

When viewing an album, one can only scroll with the cursor inside the main container (<section >id="asset-grid">). The whitespace left and right of the actual photo stream is a dead zone.

While improvable, such behavior is IMHO not all too bad for large screens (desktop). On mobile, however, it's easy to accidentally trigger a site reload while attempting to scroll on the right side of the screen, which is where my thumb usually is. This is especially annoying when a minimized background upload is canceled by the accidental refresh.

In general, this could be improved by making the entire page's width scrollable.

The OS that Immich Server is running on

Debian 10

Version of Immich Server

1.75.0

Version of Immich Mobile App

1.74.0 build.97

Platform with the issue

Your docker-compose.yml content

version: "3.8"

services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    command: [ "start.sh", "immich" ]
    volumes:
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
    env_file:
      - .env
    depends_on:
      - redis
      - database
      - typesense
    restart: always

  immich-microservices:
    container_name: immich_microservices
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    command: [ "start.sh", "microservices" ]
    volumes:
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
    env_file:
      - .env
    depends_on:
      - redis
      - database
      - typesense
    restart: always

  immich-web:
    container_name: immich_web
    image: ghcr.io/immich-app/immich-web:${IMMICH_VERSION:-release}
    env_file:
      - .env
    restart: always

  typesense:
    container_name: immich_typesense
    image: typesense/typesense:0.24.0
    environment:
      - TYPESENSE_API_KEY=${TYPESENSE_API_KEY}
      - TYPESENSE_DATA_DIR=/data
    logging:
      driver: none
    volumes:
      - tsdata:/data
    restart: always

  redis:
    container_name: immich_redis
    image: redis:6.2
    restart: always

  database:
    container_name: immich_postgres
    image: postgres:14
    env_file:
      - .env
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      PG_DATA: /var/lib/postgresql/data
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: always

  immich-proxy:
    container_name: immich_proxy
    image: ghcr.io/immich-app/immich-proxy:${IMMICH_VERSION:-release}
    environment:
      # Make sure these values get passed through from the env file
      - IMMICH_SERVER_URL
      - IMMICH_WEB_URL
    ports:
      - 2283:8080
    depends_on:
      - immich-server
    restart: always

volumes:
  pgdata:
  model-cache:
  tsdata:

Your .env content

###################################################################################
# Database
###################################################################################

# NOTE: The following four database variables support Docker secrets by adding a *_FILE suffix to the variable name
# See the docker-compose documentation on secrets for additional details: https://docs.docker.com/compose/compose-file/compose-file-v3/#secrets
DB_HOSTNAME=postgres
DB_USERNAME=postgres
DB_PASSWORD=hidden
DB_DATABASE_NAME=immich

# Optional Database settings:
# DB_PORT=5432

###################################################################################
# Redis
###################################################################################

REDIS_HOSTNAME=immich_redis

# REDIS_URL will be used to pass custom options to ioredis.
# Example for Sentinel
# {"sentinels":[{"host":"redis-sentinel-node-0","port":26379},{"host":"redis-sentinel-node-1","port":26379},{"host":"redis-sentinel-node-2","port":26379}],"name":"redis-sentinel"}
# REDIS_URL=ioredis://eyJzZW50aW5lbHMiOlt7Imhvc3QiOiJyZWRpcy1zZW50aW5lbDEiLCJwb3J0IjoyNjM3OX0seyJob3N0IjoicmVkaXMtc2VudGluZWwyIiwicG9ydCI6MjYzNzl9XSwibmFtZSI6Im15bWFzdGVyIn0=

# Optional Redis settings:

# Note: these parameters are not automatically passed to the Redis Container
# to do so, please edit the docker-compose.yml file as well. Redis is not configured
# via environment variables, only redis.conf or the command line

# REDIS_PORT=6379
# REDIS_DBINDEX=0
# REDIS_USERNAME=
# REDIS_PASSWORD=
# REDIS_SOCKET=

###################################################################################
# Upload File Location
#
# This is the location where uploaded files are stored.
###################################################################################

UPLOAD_LOCATION=/home/foo/immich-photos

###################################################################################
# Typesense
###################################################################################
TYPESENSE_API_KEY=sufpe2-vokfir-zockAx
TYPESENSE_ENABLED=true

# TYPESENSE_URL uses base64 encoding for the nodes json.
# Example JSON that was used:
# [
#      { 'host': 'typesense-1.example.net', 'port': '443', 'protocol': 'https' },
#      { 'host': 'typesense-2.example.net', 'port': '443', 'protocol': 'https' },
#      { 'host': 'typesense-3.example.net', 'port': '443', 'protocol': 'https' },
#  ]
# TYPESENSE_URL=ha://WwogICAgeyAnaG9zdCc6ICd0eXBlc2Vuc2UtMS5leGFtcGxlLm5ldCcsICdwb3J0JzogJzQ0MycsICdwcm90b2NvbCc6ICdodHRwcycgfSwKICAgIHsgJ2hvc3QnOiAndHlwZXNlbnNlLTIuZXhhbXBsZS5uZXQnLCAncG9ydCc6ICc0NDMnLCAncHJvdG9jb2wnOiAnaHR0cHMnIH0sCiAgICB7ICdob3N0JzogJ3R5cGVzZW5zZS0zLmV4YW1wbGUubmV0JywgJ3BvcnQnOiAnNDQzJywgJ3Byb3RvY29sJzogJ2h0dHBzJyB9LApd

###################################################################################
# Reverse Geocoding
#
# Reverse geocoding is done locally which has a small impact on memory usage
# This memory usage can be altered by changing the REVERSE_GEOCODING_PRECISION variable
# This ranges from 0-3 with 3 being the most precise
# 3 - Cities > 500 population: ~200MB RAM
# 2 - Cities > 1000 population: ~150MB RAM
# 1 - Cities > 5000 population: ~80MB RAM
# 0 - Cities > 15000 population: ~40MB RAM
####################################################################################

# DISABLE_REVERSE_GEOCODING=false
# REVERSE_GEOCODING_PRECISION=3

####################################################################################
# WEB - Optional
#
# Custom message on the login page, should be written in HTML form.
# For example:
# PUBLIC_LOGIN_PAGE_MESSAGE="This is a demo instance of Immich.<br><br>Email: <i>demo@demo.de</i><br>Password: <i>demo</i>"
####################################################################################

PUBLIC_LOGIN_PAGE_MESSAGE=

####################################################################################
# Alternative Service Addresses - Optional
#
# This is an advanced feature for users who may be running their immich services on different hosts.
# It will not change which address or port that services bind to within their containers, but it will change where other services look for their peers.
# Note: immich-microservices is bound to 3002, but no references are made
####################################################################################

IMMICH_WEB_URL=http://immich-web:3000
IMMICH_SERVER_URL=http://immich-server:3001
IMMICH_MACHINE_LEARNING_URL=http://192.168.178.38:3003
#IMMICH_MACHINE_LEARNING_URL=true

#IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003
#IMMICH_MACHINE_LEARNING_URL=false

####################################################################################
# Alternative API's External Address - Optional
#
# This is an advanced feature used to control the public server endpoint returned to clients during Well-known discovery.
# You should only use this if you want mobile apps to access the immich API over a custom URL. Do not include trailing slash.
# NOTE: At this time, the web app will not be affected by this setting and will continue to use the relative path: /api
# Examples: http://localhost:3001, http://immich-api.example.com, etc
####################################################################################

#IMMICH_API_URL_EXTERNAL=http://localhost:3001

###################################################################################
# Immich Version - Optional
#
# This allows all immich docker images to be pinned to a specific version. By default,
# the version is "release" but could be a specific version, like "v1.59.0".
###################################################################################

#IMMICH_VERSION=

Reproduction steps

1. View an album on mobile (Android 10, Chrome 116.0.5845.114).
2. Attempt to scroll on the white space left and right of the main photo stream.
3. Scrolling is not registered. Instead, Chrome triggers a reload event.

Additional information

No response

brianjaustin commented 1 year ago

I thought this might be a good issue to flex my frontend skills (full disclosure, it's been awhile); I've done some poking at it, but I haven't been able to get something working that doesn't have drawbacks. I've written up a little bit about each below, in case someone else wants to pick this up (or if someone has ideas to push in the right direction :slightly_smiling_face: ).

<main> Height

Changing <main> on the album page from h-screen to h-full https://github.com/immich-app/immich/blob/5156d761940df1ae2a7b99a4dba190e03f8d3cb7/web/src/routes/(user)/albums/%5BalbumId%5D/%2Bpage.svelte#L420 results in being able to scroll the page from either side. However, The timeline scrollbar disappears from the DOM, to be replaced by the default scrollbar. I tried a few different ways to make it (the default scrollbar) go away, but none worked for me in Firefox or Chromium The header becomes outlined in a lighter color when content is underneath it.

Screenshot ![Immich UI with photo grid underneath the top menu. The top menu is highlighted with a grey border. Additionally, the custom scrollbar is hidden.](https://github.com/immich-app/immich/assets/13002992/b91bb1dc-269c-4cc0-bce5-a28b7a46c416)
Diff ```diff diff --git a/web/src/routes/(user)/albums/[albumId]/+page.svelte b/web/src/routes/(user)/albums/[albumId]/+page.svelte index 2c037f8d..6994a763 100644 --- a/web/src/routes/(user)/albums/[albumId]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId]/+page.svelte @@ -418,7 +418,7 @@
{#if viewMode === ViewMode.SELECT_ASSETS} ```

Margins Within Asset Grid

Pulling the sm:px-12 md:px-24 lg:px-40 from <main> https://github.com/immich-app/immich/blob/5156d761940df1ae2a7b99a4dba190e03f8d3cb7/web/src/routes/(user)/albums/%5BalbumId%5D/%2Bpage.svelte#L420 into AssetGrid https://github.com/immich-app/immich/blob/5156d761940df1ae2a7b99a4dba190e03f8d3cb7/web/src/lib/components/photos-page/asset-grid.svelte#L328 does make some of the empty space on the album page scrollable. This isn’t free from drawbacks either though:

  1. It changes how the grid appears other places, like the user’s photos page, where it’s not desirable to have gaps around the side. (This could probably be passed in as a property from only pages where it makes sense.)
  2. The spacing now appears uneven and in need of more tweaking.
  3. There’s still part of the screen on either side (more noticeable on the right) where scrolling doesn’t work due to the margins.
Screenshot ![Immich UI with album image grid off centre](https://github.com/immich-app/immich/assets/13002992/15bad25c-225a-45b0-be97-a1f0aa13457f)
Diff ```diff diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index 4fab2662..226d06a1 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -327,7 +327,7 @@
{#if viewMode === ViewMode.SELECT_ASSETS} ```

Make the Grid Full Screen

This suffers from the same margin problem as the second attempt, and doesn’t really make a difference on mobile – at least not on an iPhone XR. It does make the experience a bit better on a desktop though, and personally I like more screen real estate being used for content versus empty space.

Screenshot ![Immich album UI with photo grid taking up most of the screen horizontally](https://github.com/immich-app/immich/assets/13002992/0974cc1b-acbd-4b51-85ea-2fe96763847a)
Diff ```diff diff --git a/web/src/routes/(user)/albums/[albumId]/+page.svelte b/web/src/routes/(user)/albums/[albumId]/+page.svelte index 2c037f8d..b64eb80e 100644 --- a/web/src/routes/(user)/albums/[albumId]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId]/+page.svelte @@ -418,7 +418,7 @@
{#if viewMode === ViewMode.SELECT_ASSETS} ```

Other Observations

Again on an iPhone XR, the album view needed to be zoomed out. When I did that, I found myself wondering if the issue is that the Immich scrollbar wasn’t draggable. Maybe changing the on:mouse* events there to on:pointer* would help? I ran into issues testing that though, so I can’t say 100%.

Diff ```diff diff --git a/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte b/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte index da028f68..333d19fc 100644 --- a/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte +++ b/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte @@ -65,15 +65,15 @@ style:height={height + 'px'} style:background-color={isDragging ? 'transparent' : 'transparent'} draggable="false" - on:mouseenter={() => (isHover = true)} - on:mouseleave={() => { + on:pointerenter={() => (isHover = true)} + on:pointerleave={() => { isHover = false; isDragging = false; }} - on:mouseenter={({ clientY, buttons }) => handleMouseEvent({ clientY, isDragging: !!buttons })} + on:pointerenter={({ clientY, buttons }) => handleMouseEvent({ clientY, isDragging: !!buttons })} on:mousemove={({ clientY }) => handleMouseEvent({ clientY })} - on:mousedown={({ clientY }) => handleMouseEvent({ clientY, isDragging: true })} - on:mouseup={({ clientY }) => handleMouseEvent({ clientY, isDragging: false })} + on:pointerdown={({ clientY }) => handleMouseEvent({ clientY, isDragging: true })} + on:pointerup={({ clientY }) => handleMouseEvent({ clientY, isDragging: false })} > {#if isHover}
ChokunPlayZ commented 11 months ago

since this never got fixed, I don't know if it slipped past the devs but I made a quick workaround using CSS.
just drop this into the custom CSS in the theme settings, clear your cache and it should fix this issue.
there's other stuff in the file too, you can remove things you don't want, the fix for this exact problem itself is just a 4 line CSS.
https://gist.github.com/ChokunPlayZ/eec78effcc0d02b98be9e2fd7d70e925

jrasm91 commented 2 months ago

I believe this is fixed as we don't ever use the asset grid with a margin, like we used to have in the album page.