Commit e7c8e493 authored by isstuev's avatar isstuev

nft fullscreen view

parent aebc6296
......@@ -9,6 +9,7 @@ const NftFallback = () => {
as={ nftIcon }
p="50px"
color={ useColorModeValue('blackAlpha.500', 'whiteAlpha.500') }
bgColor={ useColorModeValue('blackAlpha.50', 'whiteAlpha.50') }
/>
);
};
......
import { chakra } from '@chakra-ui/react';
import { chakra, LinkOverlay } from '@chakra-ui/react';
import React from 'react';
interface Props {
src: string;
onLoad: () => void;
onError: () => void;
onClick?: () => void;
}
const NftHtml = ({ src, onLoad, onError }: Props) => {
const NftHtml = ({ src, onLoad, onError, onClick }: Props) => {
return (
<chakra.iframe
src={ src }
sandbox="allow-scripts"
onLoad={ onLoad }
onError={ onError }
/>
<LinkOverlay
onClick={ onClick }
cursor="pointer"
transitionProperty="transform"
transitionDuration="normal"
transitionTimingFunction="ease"
_hover={{
transform: 'scale(1.2)',
}}
>
<chakra.iframe
src={ src }
h="100%"
w="100%"
sandbox="allow-scripts"
onLoad={ onLoad }
onError={ onError }
/>
</LinkOverlay>
);
};
......
import { chakra, useDisclosure } from '@chakra-ui/react';
import React from 'react';
import NftHtml from './NftHtml';
import NftMediaFullscreenModal from './NftMediaFullscreenModal';
interface Props {
src: string;
onLoad: () => void;
onError: () => void;
}
const NftHtmlWithFullscreen = ({ src, onLoad, onError }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<NftHtml src={ src } onLoad={ onLoad } onError={ onError } onClick={ onOpen }/>
<NftMediaFullscreenModal isOpen={ isOpen } onClose={ onClose }>
<chakra.iframe
w="90vw"
h="90vh"
src={ src }
sandbox="allow-scripts"
onLoad={ onLoad }
onError={ onError }
/>
</NftMediaFullscreenModal>
</>
);
};
export default NftHtmlWithFullscreen;
......@@ -2,20 +2,29 @@ import { Image } from '@chakra-ui/react';
import React from 'react';
interface Props {
url: string;
src: string;
onLoad: () => void;
onError: () => void;
onClick?: () => void;
}
const NftImage = ({ url, onLoad, onError }: Props) => {
const NftImage = ({ src, onLoad, onError, onClick }: Props) => {
return (
<Image
w="100%"
h="100%"
src={ url }
src={ src }
alt="Token instance image"
onError={ onError }
onLoad={ onLoad }
onClick={ onClick }
transitionProperty="transform"
transitionDuration="normal"
transitionTimingFunction="ease"
cursor="pointer"
_hover={{
transform: 'scale(1.2)',
}}
/>
);
};
......
import {
Image,
useDisclosure,
} from '@chakra-ui/react';
import React from 'react';
import NftImage from './NftImage';
import NftMediaFullscreenModal from './NftMediaFullscreenModal';
interface Props {
src: string;
onLoad: () => void;
onError: () => void;
}
const NftImageWithFullscreen = ({ src, onLoad, onError }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<NftImage src={ src } onLoad={ onLoad } onError={ onError } onClick={ onOpen }/>
<NftMediaFullscreenModal isOpen={ isOpen } onClose={ onClose }>
<Image src={ src } alt="Token instance image" maxH="90vh" w="100%" maxW="90vw"/>
</NftMediaFullscreenModal>
</>
);
};
export default NftImageWithFullscreen;
......@@ -5,56 +5,115 @@ import TestApp from 'playwright/TestApp';
import NftMedia from './NftMedia';
test.use({ viewport: { width: 250, height: 250 } });
test.describe('no url', () => {
test.use({ viewport: { width: 250, height: 250 } });
test('preview +@dark-mode', async({ mount }) => {
const component = await mount(
<TestApp>
<NftMedia url={ null }/>
</TestApp>,
);
test('no url +@dark-mode', async({ mount }) => {
const component = await mount(
<TestApp>
<NftMedia url={ null }/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
});
test.describe('image', () => {
test.use({ viewport: { width: 250, height: 250 } });
const MEDIA_URL = 'https://localhost:3000/my-image.jpg';
await expect(component).toHaveScreenshot();
test.beforeEach(async({ page }) => {
await page.route(MEDIA_URL, (route) => {
return route.fulfill({
status: 200,
path: './playwright/mocks/image_long.jpg',
});
});
});
test('preview +@dark-mode', async({ mount }) => {
const component = await mount(
<TestApp>
<NftMedia url={ MEDIA_URL }/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test('preview hover', async({ mount }) => {
const component = await mount(
<TestApp>
<NftMedia url={ MEDIA_URL }/>
</TestApp>,
);
await component.hover();
await expect(component).toHaveScreenshot();
});
});
test('image +@dark-mode', async({ mount, page }) => {
test('image fullscreen +@dark-mode +@mobile', async({ mount, page }) => {
const MEDIA_URL = 'https://localhost:3000/my-image.jpg';
await page.route(MEDIA_URL, (route) => {
return route.fulfill({
status: 200,
path: './playwright/mocks/image_long.jpg',
});
});
const component = await mount(
<TestApp>
<NftMedia url={ MEDIA_URL }/>
<NftMedia url={ MEDIA_URL } withFullscreen w="250px"/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
await component.getByAltText('Token instance image').click();
await expect(page).toHaveScreenshot();
});
test('page', async({ mount, page }) => {
test.describe('page', () => {
test.use({ viewport: { width: 250, height: 250 } });
const MEDIA_URL = 'https://localhost:3000/page.html';
const MEDIA_TYPE_API_URL = `/node-api/media-type?url=${ encodeURIComponent(MEDIA_URL) }`;
await page.route(MEDIA_URL, (route) => {
return route.fulfill({
status: 200,
path: './playwright/mocks/page.html',
test.beforeEach(async({ page }) => {
await page.route(MEDIA_URL, (route) => {
return route.fulfill({
status: 200,
path: './playwright/mocks/page.html',
});
});
await page.route(MEDIA_TYPE_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify({ type: 'html' }),
}));
});
await page.route(MEDIA_TYPE_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify({ type: 'html' }),
}));
const component = await mount(
<TestApp>
<NftMedia url={ MEDIA_URL }/>
</TestApp>,
);
test('preview +@dark-mode', async({ mount }) => {
const component = await mount(
<TestApp>
<NftMedia url={ MEDIA_URL }/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
await expect(component).toHaveScreenshot();
});
test('preview hover', async({ mount }) => {
const component = await mount(
<TestApp>
<NftMedia url={ MEDIA_URL }/>
</TestApp>,
);
await component.hover();
await expect(component).toHaveScreenshot();
});
});
import { AspectRatio, chakra, Skeleton, useColorModeValue } from '@chakra-ui/react';
import { AspectRatio, chakra, Skeleton } from '@chakra-ui/react';
import React from 'react';
import { useInView } from 'react-intersection-observer';
import NftFallback from './NftFallback';
import NftHtml from './NftHtml';
import NftHtmlWithFullscreen from './NftHtmlWithFullscreen';
import NftImage from './NftImage';
import NftImageWithFullscreen from './NftImageWithFullscreen';
import NftVideo from './NftVideo';
import NftVideoWithFullscreen from './NftVideoWithFullscreen';
import useNftMediaType from './useNftMediaType';
interface Props {
url: string | null;
className?: string;
isLoading?: boolean;
withFullscreen?: boolean;
}
const NftMedia = ({ url, className, isLoading }: Props) => {
const NftMedia = ({ url, className, isLoading, withFullscreen }: Props) => {
const [ isMediaLoading, setIsMediaLoading ] = React.useState(Boolean(url));
const [ isLoadingError, setIsLoadingError ] = React.useState(false);
const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const { ref, inView } = useInView({ triggerOnce: true });
const type = useNftMediaType(url, !isLoading && inView);
......@@ -37,13 +39,19 @@ const NftMedia = ({ url, className, isLoading }: Props) => {
return <NftFallback/>;
}
const props = {
src: url,
onLoad: handleMediaLoaded,
onError: handleMediaLoadError,
};
switch (type) {
case 'video':
return <NftVideo src={ url } onLoad={ handleMediaLoaded } onError={ handleMediaLoadError }/>;
return withFullscreen ? <NftVideoWithFullscreen { ...props }/> : <NftVideo { ...props }/>;
case 'html':
return <NftHtml src={ url } onLoad={ handleMediaLoaded } onError={ handleMediaLoadError }/>;
return withFullscreen ? <NftHtmlWithFullscreen { ...props }/> : <NftHtml { ...props }/>;
case 'image':
return <NftImage url={ url } onLoad={ handleMediaLoaded } onError={ handleMediaLoadError }/>;
return withFullscreen ? <NftImageWithFullscreen { ...props }/> : <NftImage { ...props }/>;
default:
return null;
}
......@@ -53,11 +61,11 @@ const NftMedia = ({ url, className, isLoading }: Props) => {
<AspectRatio
ref={ ref }
className={ className }
bgColor={ isLoading || isMediaLoading ? 'transparent' : bgColor }
ratio={ 1 / 1 }
overflow="hidden"
borderRadius="md"
objectFit="contain"
isolation="isolate"
sx={{
'&>img, &>video': {
objectFit: 'contain',
......
import {
Modal,
ModalContent,
ModalCloseButton,
ModalOverlay,
} from '@chakra-ui/react';
import React from 'react';
interface Props {
isOpen: boolean;
onClose: () => void;
children: React.ReactNode;
}
const NftMediaFullscreenModal = ({ isOpen, onClose, children }: Props) => {
return (
<Modal isOpen={ isOpen } onClose={ onClose } motionPreset="none">
<ModalOverlay/>
<ModalContent w="unset" maxW="100vw" p={ 0 }>
<ModalCloseButton position="fixed" color="whiteAlpha.800"/>
{ children }
</ModalContent>
</Modal>
);
};
export default NftMediaFullscreenModal;
......@@ -5,9 +5,10 @@ interface Props {
src: string;
onLoad: () => void;
onError: () => void;
onClick?: () => void;
}
const NftVideo = ({ src, onLoad, onError }: Props) => {
const NftVideo = ({ src, onLoad, onError, onClick }: Props) => {
return (
<chakra.video
src={ src }
......@@ -19,6 +20,14 @@ const NftVideo = ({ src, onLoad, onError }: Props) => {
onCanPlayThrough={ onLoad }
onError={ onError }
borderRadius="md"
onClick={ onClick }
transitionProperty="transform"
transitionDuration="normal"
transitionTimingFunction="ease"
cursor="pointer"
_hover={{
transform: 'scale(1.2)',
}}
/>
);
};
......
import {
chakra,
useDisclosure,
} from '@chakra-ui/react';
import React from 'react';
import NftMediaFullscreenModal from './NftMediaFullscreenModal';
import NftVideo from './NftVideo';
interface Props {
src: string;
onLoad: () => void;
onError: () => void;
}
const NftVideoWithFullscreen = ({ src, onLoad, onError }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<NftVideo src={ src } onLoad={ onLoad } onError={ onError } onClick={ onOpen }/>
<NftMediaFullscreenModal isOpen={ isOpen } onClose={ onClose }>
<chakra.video
src={ src }
autoPlay
disablePictureInPicture
loop
muted
playsInline
onCanPlayThrough={ onLoad }
onError={ onError }
maxH="90vh"
maxW="90vw"
/>
</NftMediaFullscreenModal>
</>
);
};
export default NftVideoWithFullscreen;
......@@ -88,6 +88,7 @@ const TokenInstanceDetails = ({ data, scrollRef, isLoading }: Props) => {
flexShrink={ 0 }
alignSelf={{ base: 'center', lg: 'flex-start' }}
isLoading={ isLoading }
withFullscreen
/>
</Flex>
<Grid
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment