Image modal for item page

main
Ashelyn Dawn 3 years ago
parent f80303cc29
commit ca3e9050cc

@ -1,3 +1,4 @@
import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom'
import {Icon} from '@rmwc/icon'
import FocusTrap from 'focus-trap-react'
@ -5,15 +6,29 @@ import FocusTrap from 'focus-trap-react'
import styles from './modal.module.css'
export default function Modal({visible, title, children, onDeactivate}){
if(typeof window === 'undefined')
const [portalExists, setPortalExists] = useState(false);
useEffect(() => {
const portalExists = !!document.querySelector('#sos-modal');
if (!portalExists) {
const portal = document.createElement('div');
portal.id = '#sos-modal';
document.body.appendChild(portal);
}
setPortalExists(true);
}, []);
if(!portalExists)
return null
return ReactDOM.createPortal((
<div className={styles.modalContainer + (visible?' ' + styles.modalShown:'')}>
<div className={styles.modalBackground}/>
<div className={styles.modalBackground} onClick={onDeactivate}/>
{visible && (
<FocusTrap active={visible} focusTrapOptions={{onDeactivate}}>
<div className={styles.modalScroll} onClick={onDeactivate}>
<div className={styles.modalScroll}>
<dialog open className={styles.modal}>
<div className={styles.titleContainer}>
<h2>{title}</h2>

@ -31,10 +31,13 @@
.modalScroll {
overflow-y: auto;
cursor: pointer;
pointer-events: none;
z-index: 11;
}
.modal {
cursor: auto;
pointer-events: all;
border: none;
margin: 100px auto;
max-width: 600px;

@ -4,6 +4,9 @@ import Router from 'next/router'
import {FormController, IntegerInput, Button} from '~/components/form'
import isNum from 'validator/lib/isNumeric'
import {DateTime} from 'luxon'
import {Icon} from '@rmwc/icon'
import Modal from '~/components/modal'
import useCart, {useSetCart} from '~/hooks/useCart'
import styles from './style.module.css'
@ -24,13 +27,13 @@ Item.getInitialProps = async function({ctx: {axios, query: {slug}}}){
return {item}
}
// TODO: Modal with full image size on clicking preview
export default function Item({item}){
const cart = useCart()
const setCart = useSetCart()
// Pick first one with featured flag or 0
const featuredIndex = item.images.reduce((p, im, i) => ((p !== undefined) ? p : (im.featured ? i : undefined)), undefined) || 0
const [selectedIndex, setSelected] = useState(featuredIndex);
const [imageModalVisible, setImageModalVisible] = useState(false);
const numInCart = cart?.items?.find(i => i.item.uuid === item.uuid)?.count || 0
@ -57,8 +60,8 @@ export default function Item({item}){
<div className={styles.imageContainer}>
<div className={styles.card}>
<picture>
<source srcset={`/api/images/${item.images[selectedIndex].uuid}/thumb.webp`} type="image/webp"/>
<img src={`/api/images/${item.images[selectedIndex].uuid}/thumb.png`} />
<source srcSet={`/api/images/${item.images[selectedIndex].uuid}/thumb.webp`} type="image/webp"/>
<img src={`/api/images/${item.images[selectedIndex].uuid}/thumb.png`} onClick={() => setImageModalVisible(true)} />
</picture>
</div>
{item.images && item.images.length > 1 &&
@ -75,6 +78,22 @@ export default function Item({item}){
))}
</div>
}
<Modal title={`${item.name} (Image ${selectedIndex + 1})`} visible={imageModalVisible} onDeactivate={() => setImageModalVisible(false)}>
<div className={styles.imageCarousel}>
<button onClick={() => setSelected(index => (index - 1 < 0) ? item.images.length - 1 : index - 1)}>
<Icon icon="chevron_left" />
</button>
<div className={styles.fullImage}>
<picture>
<source srcSet={`/api/images/${item.images[selectedIndex].uuid}/large.webp`} type="image/webp"/>
<img src={`/api/images/${item.images[selectedIndex].uuid}/large.png`} onClick={() => setImageModalVisible(true)} />
</picture>
</div>
<button onClick={() => setSelected(index => (index + 1) % item.images.length)}>
<Icon icon="chevron_right" />
</button>
</div>
</Modal>
</div>
)}
<div className={styles.controls}>

@ -100,4 +100,29 @@
.form > div {
margin-left: 0;
width: 100%;
}
.imageCarousel {
margin-top: 8px;
display: flex;
align-items: stretch;
}
.imageCarousel button {
background: none;
border: none;
cursor: pointer;
}
.imageCarousel button:hover {
background: rgba(0,0,0,0.12);
}
.fullImage {
max-width: 100%;
}
.fullImage img {
width: 100%;
height: auto;
}
Loading…
Cancel
Save