From c0bd1ac516bd5f22e73778038820a8f7844e827c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Pe=CC=81ault?= Date: Thu, 11 Nov 2021 23:32:41 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5=20Make=20the=20photo=20viewer=20co?= =?UTF-8?q?mpletely=20working?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merci Grafikart 🙏 A whole bunch of headaches and challenges to load prev and next photos depending on the current one, while animating everything nicely. Added lots of comments to document the logic and fetching. --- .../[country]/[location]/[photo].svelte | 196 ++++++++++++++---- src/style/pages/_viewer-photo.scss | 71 +++++-- 2 files changed, 207 insertions(+), 60 deletions(-) diff --git a/src/routes/[country]/[location]/[photo].svelte b/src/routes/[country]/[location]/[photo].svelte index ed4c743..82fb903 100644 --- a/src/routes/[country]/[location]/[photo].svelte +++ b/src/routes/[country]/[location]/[photo].svelte @@ -1,6 +1,8 @@ @@ -87,9 +165,9 @@
@@ -120,7 +198,7 @@

{currentPhoto.title}

- {location.name}, {location.country.name} · + {location.name}, {location.country.name} ·
@@ -132,12 +210,45 @@ import { fetchAPI } from '$utils/api' export async function load ({ page, fetch, session, stuff }) { + // Get the first photo ID + const firstPhoto = await fetchAPI(` + query { + photo: photo (search: "${page.params.photo}") { + id + } + } + `) + const firstPhotoId = firstPhoto?.data?.photo[0]?.id + // TODO: use same request for both queries (photo.id) + const photosBeforeFirst = await fetchAPI(` + query { + count: photo_aggregated ( + filter: { + id: { _gt: ${firstPhotoId} }, + location: { slug: { _eq: "${page.params.location}" }}, + status: { _eq: "published" }, + }, + sort: "-id", + ) { + count { + id + } + } + } + `) + // Define offset from the current count + const offset = Math.max(photosBeforeFirst?.data?.count[0]?.count.id - 5, 0) + const limit = 10 const res = await fetchAPI(` query { photos: photo ( - filter: { location: { slug: { _eq: "${page.params.location}" }}}, + filter: { + location: { slug: { _eq: "${page.params.location}" }} + status: { _eq: "published" }, + }, sort: "-date_created", - limit: 5, + limit: ${limit}, + offset: ${offset}, ) { id title @@ -162,15 +273,16 @@ const totalPhotos = stuff.countTotalPhotosByLocation.find((total: any) => total.group.location === Number(location.id)).count.id // Find photo's index - const currentPhotoIndex = data.photos.findIndex((photo: any) => photo.slug === page.params.photo) - const currentIndex = (totalPhotos - 1) - currentPhotoIndex + const currentIndex = data.photos.findIndex((photo: any) => photo.slug === page.params.photo) return { props: { photos: data.photos, location: data.location[0], currentIndex, - totalPhotos, + countPhotos: totalPhotos, + limit, + offset, } } } diff --git a/src/style/pages/_viewer-photo.scss b/src/style/pages/_viewer-photo.scss index e461d61..913dcd4 100644 --- a/src/style/pages/_viewer-photo.scss +++ b/src/style/pages/_viewer-photo.scss @@ -50,17 +50,23 @@ display: block; width: 100%; height: 100%; - z-index: 3; + z-index: 8; overflow: hidden; + opacity: 0; transform: translate3d(var(--offset-x), var(--offset-y), 0) scale(var(--scale)) rotate(var(--rotate)); transform-origin: top center; cursor: default; will-change: transform; transition: opacity 1s var(--ease-quart), transform 1s var(--ease-quart); + --scale: 0.6; + --offset-x: 20%; + --offset-y: -64%; + opacity: 0; @include bp (md) { - --offset-x: 0%; - --offset-y: -50%; + --offset-x: 13%; + --offset-y: -65%; + --rotate: 5deg; top: 50%; left: 0; transform-origin: bottom right; @@ -75,36 +81,67 @@ transform: translateZ(0); } - &:nth-child(2) { + // Hidden photo over + &--0 { + --scale: 1.1; + --rotate: -1deg; + z-index: 9; + opacity: 0; + + @include bp (md) { + --offset-x: -5%; + --offset-y: -45%; + } + } + // First visible photo + &--1 { + --scale: 1; + --rotate: 0deg; + opacity: 1; + box-shadow: + 0 12px 12px rgba(#000, 0.15), + 0 20px 20px rgba(#000, 0.15), + 0 48px 48px rgba(#000, 0.15); + + @include bp (md) { + --offset-x: 0%; + --offset-y: -50%; + } + } + &--2 { --scale: 0.9; --opacity: 0.75; --offset-y: -34%; z-index: 7; + opacity: 1; @include bp (md) { --scale: 0.9; --rotate: 1deg; - --offset-x: 4.5%; + --offset-x: 3.75%; --offset-y: -54%; } } - &:nth-child(3) { + &--3 { --scale: 0.83; --opacity: 0.55; --offset-y: -22.5%; z-index: 6; + opacity: 1; @include bp (md) { --scale: 0.83; - --offset-x: 7%; + --rotate: 2deg; + --offset-x: 6.5%; --offset-y: -56.5%; } } - &:nth-child(4) { + &--4 { --scale: 0.75; --opacity: 0.45; --offset-y: -11%; z-index: 5; + opacity: 1; @include bp (md) { --scale: 0.75; @@ -113,11 +150,12 @@ --offset-y: -59%; } } - &:nth-child(5) { + &--5 { --scale: 0.68; --opacity: 0.3; --offset-y: -1.5%; z-index: 4; + opacity: 1; @include bp (md) { --scale: 0.68; @@ -126,14 +164,10 @@ --offset-y: -61.5%; } } - - // Active state - &.is-active { - z-index: 8; - box-shadow: - 0 12px 12px rgba(#000, 0.15), - 0 20px 20px rgba(#000, 0.15), - 0 48px 48px rgba(#000, 0.15); + &--6 { + --opacity: 0.3; + z-index: 3; + opacity: 0; } } } @@ -152,7 +186,7 @@ } @include bp (lg) { display: grid; - grid-template-columns: 55% 45%; + grid-template-columns: 60% 40%; align-items: baseline; } @@ -211,6 +245,7 @@ line-height: 1; color: rgba($color-tertiary, 0.4); transform: translate3d(-50%, 0, 0); + white-space: nowrap; @include bp (md, max) { font-size: clamp(#{rem(80px)}, 24vw, #{rem(120px)});