From d77070a210bd526513bbf880cd91c4c0ed7f8d71 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Tue, 20 Aug 2024 16:31:01 +0200 Subject: [PATCH] refactor(SW-96): unify lightbox to handle mobile and desktop --- .../HotelPage/PreviewImages/index.tsx | 8 +- components/ContentType/HotelPage/data.ts | 2 +- .../Desktop/desktopLightbox.module.css | 165 ----------- components/Lightbox/Lightbox.module.css | 272 ++++++++++++++++++ components/Lightbox/{Desktop => }/index.tsx | 189 +++++++----- i18n/dictionaries/da.json | 1 + i18n/dictionaries/de.json | 1 + i18n/dictionaries/en.json | 1 + i18n/dictionaries/fi.json | 1 + i18n/dictionaries/no.json | 1 + i18n/dictionaries/sv.json | 1 + .../{desktopLightbox.ts => lightbox.ts} | 2 +- 12 files changed, 396 insertions(+), 248 deletions(-) delete mode 100644 components/Lightbox/Desktop/desktopLightbox.module.css create mode 100644 components/Lightbox/Lightbox.module.css rename components/Lightbox/{Desktop => }/index.tsx (62%) rename types/components/lightbox/{desktopLightbox.ts => lightbox.ts} (92%) diff --git a/components/ContentType/HotelPage/PreviewImages/index.tsx b/components/ContentType/HotelPage/PreviewImages/index.tsx index c8b85698e..ec18ad05d 100644 --- a/components/ContentType/HotelPage/PreviewImages/index.tsx +++ b/components/ContentType/HotelPage/PreviewImages/index.tsx @@ -1,11 +1,11 @@ import Image from "@/components/Image" -import { DesktopLightbox } from "@/components/Lightbox/Desktop" +import { Lightbox } from "@/components/Lightbox" import Button from "@/components/TempDesignSystem/Button" import { getIntl } from "@/i18n" import styles from "./previewImages.module.css" -import { ImageItem } from "@/types/components/lightbox/desktopLightbox" +import { ImageItem } from "@/types/components/lightbox/lightbox" export default async function PreviewImages({ images, @@ -14,7 +14,7 @@ export default async function PreviewImages({ }) { const intl = await getIntl() return ( - +
{/*TODO: Replace with images from API once SW-189 is merged. */} {images.slice(0, 3).map((image, index) => ( @@ -38,6 +38,6 @@ export default async function PreviewImages({ {intl.formatMessage({ id: "See all photos" })}
-
+ ) } diff --git a/components/ContentType/HotelPage/data.ts b/components/ContentType/HotelPage/data.ts index e6aa284a7..3fe2e41f4 100644 --- a/components/ContentType/HotelPage/data.ts +++ b/components/ContentType/HotelPage/data.ts @@ -3,7 +3,7 @@ import { FC } from "react" import { getIconByIconName } from "@/components/Icons/get-icon-by-icon-name" import { IconName, IconProps } from "@/types/components/icon" -import { ImageItem } from "@/types/components/lightbox/desktopLightbox" +import { ImageItem } from "@/types/components/lightbox/lightbox" const facilityToIconMap: { [key: string]: IconName } = { Bar: IconName.Bar, diff --git a/components/Lightbox/Desktop/desktopLightbox.module.css b/components/Lightbox/Desktop/desktopLightbox.module.css deleted file mode 100644 index 47c91c216..000000000 --- a/components/Lightbox/Desktop/desktopLightbox.module.css +++ /dev/null @@ -1,165 +0,0 @@ -.content { - border-radius: var(--Corner-radius-Large); - position: fixed; - top: 50%; - left: 50%; - width: 1090px; - height: 725px; - overflow: hidden; - z-index: 10; -} - -.overlay { - position: fixed; - inset: 0; - background-color: rgba(0, 0, 0, 0.5); - z-index: 10; -} - -.galleryContainer { - background-color: var(--Base-Background-Primary-Normal); - padding: var(--Spacing-x5) var(--Spacing-x6); - height: 100%; - display: flex; - flex-direction: column; - position: relative; -} - -.closeButton { - position: absolute; - top: var(--Spacing-x-one-and-half); - right: var(--Spacing-x-half); -} - -.backButton { - position: absolute; - top: var(--Spacing-x-one-and-half); - left: var(--Spacing-x-half); -} - -.galleryHeader { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--Spacing-x1); -} - -.imageCaption { - background-color: var(--Base-Surface-Subtle-Normal); - padding: var(--Spacing-x-half) var(--Spacing-x1); - border-radius: var(--Corner-radius-Small); -} - -.mainImageWrapper { - position: relative; - flex: 1; - margin-bottom: var(--Spacing-x2); -} - -.mainImageContainer { - width: 100%; - height: 100%; - will-change: transform; - overflow: hidden; -} - -.mainImageContainer img, -.thumbnailContainer img { - border-radius: var(--Corner-radius-Small); - cursor: pointer; - transition: opacity 0.3s ease-in-out; -} - -.thumbnailGrid { - display: grid; - grid-template-columns: repeat(5, 1fr); - gap: var(--Spacing-x1); - max-height: 125px; - overflow: hidden; -} - -.thumbnailContainer { - position: relative; - height: 125px; -} - -.fullViewContainer { - background-color: var(--UI-Text-High-contrast); - height: 100%; - padding: var(--Spacing-x5); - display: flex; - flex-direction: column; - align-items: center; -} - -.fullViewHeader { - display: flex; - justify-content: center; - margin-bottom: var(--Spacing-x5); - width: 100%; -} - -.fullViewImageContainer { - position: relative; - width: 100%; - max-width: 1054px; - height: 700px; - margin-bottom: var(--Spacing-x5); -} - -.fullViewImage { - position: absolute; - width: 100%; - height: 100%; -} - -.fullViewFooter { - width: 100%; - max-width: 1054px; - text-align: left; - padding-left: 116px; -} - -.imagePosition { - background-color: var(--UI-Grey-90); - padding: var(--Spacing-x-quarter) var(--Spacing-x-half); - border-radius: var(--Corner-radius-Small); -} - -.fullViewImageContainer img { - border-radius: var(--Corner-radius-Medium); - cursor: pointer; -} - -.navigationButton { - position: absolute; - top: 50%; - transform: translateY(-50%); - background-color: var(--Base-Button-Inverted-Fill-Normal); - border-radius: 50%; - padding: var(--Spacing-x1); - cursor: pointer; - border: none; - display: flex; - z-index: 1; -} - -.navigationButton:hover { - background-color: var(--Base-Button-Inverted-Fill-Hover); -} - -.prevButton { - left: var(--Spacing-x2); -} - -.leftTransformIcon { - transform: scaleX(-1); -} - -.nextButton { - right: var(--Spacing-x2); -} - -.portraitImage { - max-width: 548px; -} diff --git a/components/Lightbox/Lightbox.module.css b/components/Lightbox/Lightbox.module.css new file mode 100644 index 000000000..280b80911 --- /dev/null +++ b/components/Lightbox/Lightbox.module.css @@ -0,0 +1,272 @@ +.desktopGallery { + display: none; +} + +.mobileGallery { + margin-top: 70.047px; + height: 100%; + overflow-y: auto; + position: relative; + display: flex; + flex-direction: column; + gap: var(--Spacing-x2); +} + +.mobileGalleryContent { + display: block; +} + +.fullViewCloseButton { + position: absolute; + top: var(--Spacing-x-one-and-half); + left: var(--Spacing-x-half); + z-index: 1; +} + +.leftTransformIcon { + transform: scaleX(-1); +} + +.content { + width: 100%; + height: 100%; + border-radius: 0; + position: fixed; + top: 50%; + left: 50%; + z-index: 10; +} + +.overlay { + position: fixed; + inset: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 10; +} + +.galleryContainer { + background-color: var(--Base-Background-Primary-Normal); + padding: var(--Spacing-x2); + height: 100%; + display: flex; + flex-direction: column; + position: relative; +} + +.galleryHeader { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--Spacing-x1); +} + +.imageCaption { + background-color: var(--Base-Surface-Subtle-Normal); + padding: var(--Spacing-x-half) var(--Spacing-x1); + border-radius: var(--Corner-radius-Small); +} + +.mainImageWrapper { + position: relative; + flex: 1; + margin-bottom: var(--Spacing-x2); +} + +.mainImageContainer { + width: 100%; + height: 100%; + will-change: transform; + overflow: hidden; +} + +.mainImageContainer img, +.thumbnailContainer img { + border-radius: var(--Corner-radius-Small); + cursor: pointer; + transition: opacity 0.3s ease-in-out; +} + +.thumbnailGrid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--Spacing-x1); + max-height: none; +} + +.thumbnailContainer { + position: relative; + height: 242px; +} + +.fullWidthImage { + grid-column: 1 / -1; + height: 240px; +} + +.thumbnailContainer img { + border-radius: var(--Corner-radius-Medium); +} + +.fullViewContainer { + margin-top: 70.047px; + background-color: var(--UI-Text-High-contrast); + height: 100%; + padding: var(--Spacing-x2); + position: relative; + align-items: center; + display: grid; + grid-template-rows: auto 1fr auto; + place-content: center; +} + +.fullViewHeader { + display: flex; + justify-content: center; + margin-bottom: var(--Spacing-x5); + width: 100%; +} + +.fullViewImageContainer { + position: relative; + width: 358px; + height: 240px; + margin-bottom: var(--Spacing-x5); +} + +.fullViewImage { + position: absolute; + width: 100%; + height: 100%; + border-radius: var(--Corner-radius-Medium); +} + +.fullViewImageContainer img { + border-radius: var(--Corner-radius-Medium); + cursor: pointer; + width: 100%; + height: 100%; +} + +.fullViewFooter { + position: absolute; + bottom: calc(-1 * var(--Spacing-x5)); +} + +.imagePosition { + background-color: var(--UI-Grey-90); + padding: var(--Spacing-x-quarter) var(--Spacing-x-half); + border-radius: var(--Corner-radius-Small); +} + +.navigationButton { + display: none; +} + +.portraitImage { + max-width: 548px; +} + +@media (min-width: 1367px) { + .content { + border-radius: var(--Corner-radius-Large); + width: 1090px; + height: 725px; + overflow: hidden; + } + + .galleryContainer { + padding: var(--Spacing-x5) var(--Spacing-x6); + } + + .desktopGallery { + display: flex; + background-color: var(--Base-Background-Primary-Normal); + height: 100%; + flex-direction: column; + position: relative; + } + + .desktopGalleryCloseButton { + position: absolute; + top: var(--Spacing-x-one-and-half); + right: var(--Spacing-x-half); + } + + .mobileGallery { + display: none; + } + + .thumbnailGrid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: var(--Spacing-x1); + max-height: 125px; + overflow: hidden; + } + + .thumbnailContainer { + height: 125px; + } + + .fullViewCloseButton { + position: fixed; + } + + .fullWidthImage { + grid-column: auto; + height: auto; + } + + .thumbnailContainer img { + border-radius: var(--Corner-radius-Small); + } + + .fullViewContainer { + margin-top: 0; + padding: var(--Spacing-x5); + grid-template-rows: auto 1fr auto; + grid-template-columns: 1fr; + justify-items: center; + } + + .fullViewImageContainer { + position: relative; + max-width: 1054px; + width: 80%; + height: 85%; + margin-bottom: var(--Spacing-x5); + } + + .navigationButton { + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: var(--Base-Button-Inverted-Fill-Normal); + border-radius: 50%; + padding: var(--Spacing-x1); + cursor: pointer; + border: none; + display: flex; + z-index: 1; + } + + .galleryPrevButton { + left: var(--Spacing-x2); + } + + .galleryNextButton { + right: var(--Spacing-x2); + } + + .fullViewNextButton { + right: var(--Spacing-x5); + } + + .fullViewPrevButton { + left: var(--Spacing-x5); + } + + .fullViewFooter { + text-align: left; + } +} diff --git a/components/Lightbox/Desktop/index.tsx b/components/Lightbox/index.tsx similarity index 62% rename from components/Lightbox/Desktop/index.tsx rename to components/Lightbox/index.tsx index a68e97c61..614405467 100644 --- a/components/Lightbox/Desktop/index.tsx +++ b/components/Lightbox/index.tsx @@ -11,15 +11,15 @@ import Button from "@/components/TempDesignSystem/Button" import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" -import styles from "./desktopLightbox.module.css" +import styles from "./Lightbox.module.css" import { - DesktopLightboxProps, FullViewProps, GalleryProps, -} from "@/types/components/lightbox/desktopLightbox" + LightboxProps, +} from "@/types/components/lightbox/lightbox" -export function DesktopLightbox({ images, children }: DesktopLightboxProps) { +export function Lightbox({ images, children }: LightboxProps) { const [isOpen, setIsOpen] = useState(false) const [selectedImageIndex, setSelectedImageIndex] = useState(0) const [isFullView, setIsFullView] = useState(false) @@ -155,72 +155,108 @@ function Gallery({ intent="text" size="small" theme="base" - className={styles.closeButton} + className={styles.desktopGalleryCloseButton} onClick={onClose} > -
-
- {mainImage.alt} + {/* Desktop Gallery */} +
+
+
+ {mainImage.alt} +
-
-
- - - {mainImage.alt} - - - - - - - - -
-
- - {getThumbImages().map((image, index) => ( +
+ onSelectImage(image)} - initial={{ opacity: 0, x: 50 }} + key={mainImage.url} + className={styles.mainImageContainer} + initial={{ opacity: 0, x: 300 }} animate={{ opacity: 1, x: 0 }} - exit={{ opacity: 0, x: -50 }} - transition={{ duration: 0.2, delay: index * 0.05 }} + exit={{ opacity: 0, x: -300 }} + transition={{ duration: 0.3 }} > {image.alt} - ))} - + + + + + + + +
+
+ + {getThumbImages().map((image, index) => ( + onSelectImage(image)} + initial={{ opacity: 0, x: 50 }} + animate={{ opacity: 1, x: 0 }} + exit={{ opacity: 0, x: -50 }} + transition={{ duration: 0.2, delay: index * 0.05 }} + > + {image.alt} + + ))} + +
+
+ + {/* Mobile Gallery */} +
+ +
+
+ {images.map((image, index) => ( + onImageClick()} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.3, delay: index * 0.05 }} + > + {image.alt} + + ))} +
+
) @@ -239,7 +275,7 @@ function FullView({
-
- {image.alt}
+ + + + + + + ) } diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index e6a339181..e44cefb3a 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -144,6 +144,7 @@ "Save": "Gemme", "Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Point Shop": "Scandic Friends Point Shop", + "See all photos": "Se alle billeder", "See hotel details": "Se hoteloplysninger", "See rooms": "Se værelser", "Select a country": "Vælg et land", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index 6f730539d..72128e6ea 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -139,6 +139,7 @@ "Save": "Speichern", "Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Point Shop": "Scandic Friends Point Shop", + "See all photos": "Alle Fotos ansehen", "See hotel details": "Hotelinformationen ansehen", "See rooms": "Zimmer ansehen", "Select a country": "Wähle ein Land", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index da33379f2..9cf0294a6 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -150,6 +150,7 @@ "Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Point Shop": "Scandic Friends Point Shop", "See hotel details": "See hotel details", + "See all photos": "See all photos", "See room details": "See room details", "See rooms": "See rooms", "Select a country": "Select a country", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index d362b3dbe..265e5bb40 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -144,6 +144,7 @@ "Save": "Tallentaa", "Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Point Shop": "Scandic Friends Point Shop", + "See all photos": "Katso kaikki kuvat", "See hotel details": "Katso hotellin tiedot", "See rooms": "Katso huoneet", "Select a country": "Valitse maa", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index eeb1cfbc6..1b488e07c 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -144,6 +144,7 @@ "Save": "Lagre", "Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Point Shop": "Scandic Friends Point Shop", + "See all photos": "Se alle bilder", "See hotel details": "Se hotellinformasjon", "See rooms": "Se rom", "Select a country": "Velg et land", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index 721037d7f..77a3758d1 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -146,6 +146,7 @@ "Save": "Spara", "Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Point Shop": "Scandic Friends Point Shop", + "See all photos": "Se alla foton", "See hotel details": "Se hotellinformation", "See room details": "Se rumsdetaljer", "See rooms": "Se rum", diff --git a/types/components/lightbox/desktopLightbox.ts b/types/components/lightbox/lightbox.ts similarity index 92% rename from types/components/lightbox/desktopLightbox.ts rename to types/components/lightbox/lightbox.ts index b12e823e3..be3eaa108 100644 --- a/types/components/lightbox/desktopLightbox.ts +++ b/types/components/lightbox/lightbox.ts @@ -3,7 +3,7 @@ export interface ImageItem { alt: string } -export interface DesktopLightboxProps { +export interface LightboxProps { images: ImageItem[] children: React.ReactNode }