1
Fork 0

Rewrite gallery to use reducer

This commit is contained in:
viktorstrate 2021-04-29 23:59:28 +02:00
parent 6693cb589c
commit a069eff0b2
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
12 changed files with 309 additions and 174 deletions

2
.gitignore vendored
View File

@ -16,7 +16,7 @@ docker-compose.yml
node_modules/ node_modules/
# testing # testing
/coverage /ui/coverage
# building # building
.cache/ .cache/

View File

@ -43,7 +43,7 @@ module.exports = {
// parser: 'babel-eslint', // parser: 'babel-eslint',
overrides: [ overrides: [
Object.assign(require('eslint-plugin-jest').configs.recommended, { Object.assign(require('eslint-plugin-jest').configs.recommended, {
files: ['**/*.test.js'], files: ['**/*.test.js', '**/*.test.ts', '**/*.test.tsx'],
env: { jest: true }, env: { jest: true },
plugins: ['jest', 'jest-dom'], plugins: ['jest', 'jest-dom'],
rules: Object.assign( rules: Object.assign(

14
ui/package-lock.json generated
View File

@ -56,7 +56,7 @@
"@testing-library/jest-dom": "^5.11.10", "@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6", "@testing-library/react": "^11.2.6",
"@types/geojson": "^7946.0.7", "@types/geojson": "^7946.0.7",
"@types/jest": "^26.0.22", "@types/jest": "^26.0.23",
"@types/mapbox-gl": "^2.1.1", "@types/mapbox-gl": "^2.1.1",
"@types/react": "^17.0.3", "@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3", "@types/react-dom": "^17.0.3",
@ -2789,9 +2789,9 @@
} }
}, },
"node_modules/@types/jest": { "node_modules/@types/jest": {
"version": "26.0.22", "version": "26.0.23",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz",
"integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==", "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"jest-diff": "^26.0.0", "jest-diff": "^26.0.0",
@ -16438,9 +16438,9 @@
} }
}, },
"@types/jest": { "@types/jest": {
"version": "26.0.22", "version": "26.0.23",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz",
"integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==", "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==",
"dev": true, "dev": true,
"requires": { "requires": {
"jest-diff": "^26.0.0", "jest-diff": "^26.0.0",

View File

@ -69,7 +69,7 @@
"@testing-library/jest-dom": "^5.11.10", "@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6", "@testing-library/react": "^11.2.6",
"@types/geojson": "^7946.0.7", "@types/geojson": "^7946.0.7",
"@types/jest": "^26.0.22", "@types/jest": "^26.0.23",
"@types/mapbox-gl": "^2.1.1", "@types/mapbox-gl": "^2.1.1",
"@types/react": "^17.0.3", "@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3", "@types/react-dom": "^17.0.3",
@ -97,6 +97,10 @@
"arrowParens": "avoid" "arrowParens": "avoid"
}, },
"jest": { "jest": {
"testMatch": [
"**/__tests__/**/*.+(ts|tsx|js)",
"**/?(*.)+(spec|test).+(ts|tsx|js)"
],
"transformIgnorePatterns": [ "transformIgnorePatterns": [
"^.+\\.css$" "^.+\\.css$"
], ],

View File

@ -1,10 +1,11 @@
import React, { useState, useEffect } from 'react' import React, { useReducer } from 'react'
import AlbumTitle from '../AlbumTitle' import AlbumTitle from '../AlbumTitle'
import PhotoGallery from '../photoGallery/PhotoGallery' import PhotoGallery from '../photoGallery/PhotoGallery'
import AlbumBoxes from './AlbumBoxes' import AlbumBoxes from './AlbumBoxes'
import AlbumFilter from '../AlbumFilter' import AlbumFilter from '../AlbumFilter'
import { albumQuery_album } from '../../Pages/AlbumPage/__generated__/albumQuery' import { albumQuery_album } from '../../Pages/AlbumPage/__generated__/albumQuery'
import { OrderDirection } from '../../../__generated__/globalTypes' import { OrderDirection } from '../../../__generated__/globalTypes'
import { photoGalleryReducer } from '../photoGallery/photoGalleryReducer'
type AlbumGalleryProps = { type AlbumGalleryProps = {
album?: albumQuery_album album?: albumQuery_album
@ -29,71 +30,49 @@ const AlbumGallery = React.forwardRef(
setOrdering, setOrdering,
ordering, ordering,
onlyFavorites = false, onlyFavorites = false,
onFavorite,
}: AlbumGalleryProps, }: AlbumGalleryProps,
ref: React.ForwardedRef<HTMLDivElement> ref: React.ForwardedRef<HTMLDivElement>
) => { ) => {
type ImageStateType = { // const [imageState, setImageState] = useState<ImageStateType>({
activeImage: number // activeImage: -1,
presenting: boolean // presenting: false,
} // })
const [imageState, setImageState] = useState<ImageStateType>({ const [mediaState, dispatchMedia] = useReducer(photoGalleryReducer, {
activeImage: -1,
presenting: false, presenting: false,
activeIndex: -1,
media: album?.media || [],
}) })
const setPresenting = (presenting: boolean) => // const setPresentingWithHistory = (presenting: boolean) => {
setImageState(state => ({ ...state, presenting })) // setPresenting(presenting)
// if (presenting) {
// history.pushState({ imageState }, '')
// } else {
// history.back()
// }
// }
const setPresentingWithHistory = (presenting: boolean) => { // const updateHistory = (imageState: ImageStateType) => {
setPresenting(presenting) // history.replaceState({ imageState }, '')
if (presenting) { // return imageState
history.pushState({ imageState }, '') // }
} else {
history.back()
}
}
const updateHistory = (imageState: ImageStateType) => { // useEffect(() => {
history.replaceState({ imageState }, '') // const updateImageState = (event: PopStateEvent) => {
return imageState // setImageState(event.state.imageState)
} // }
const setActiveImage = (activeImage: number) => { // window.addEventListener('popstate', updateImageState)
setImageState(state => updateHistory({ ...state, activeImage }))
}
const nextImage = () => { // return () => {
if (album === undefined) return // window.removeEventListener('popstate', updateImageState)
setActiveImage((imageState.activeImage + 1) % album.media.length) // }
} // }, [imageState])
const previousImage = () => { // useEffect(() => {
if (album === undefined) return // setActiveImage(-1)
// }, [album])
if (imageState.activeImage <= 0) {
setActiveImage(album.media.length - 1)
} else {
setActiveImage(imageState.activeImage - 1)
}
}
useEffect(() => {
const updateImageState = (event: PopStateEvent) => {
setImageState(event.state.imageState)
}
window.addEventListener('popstate', updateImageState)
return () => {
window.removeEventListener('popstate', updateImageState)
}
}, [imageState])
useEffect(() => {
setActiveImage(-1)
}, [album])
let subAlbumElement = null let subAlbumElement = null
@ -135,16 +114,8 @@ const AlbumGallery = React.forwardRef(
} }
<PhotoGallery <PhotoGallery
loading={loading} loading={loading}
media={album?.media || []} mediaState={mediaState}
activeIndex={imageState.activeImage} dispatchMedia={dispatchMedia}
presenting={imageState.presenting}
onSelectImage={index => {
setActiveImage(index)
}}
onFavorite={onFavorite}
setPresenting={setPresentingWithHistory}
nextImage={nextImage}
previousImage={previousImage}
/> />
</div> </div>
) )

View File

@ -1,22 +1,8 @@
import React, { useCallback, useState } from 'react' import React, { useCallback, useState } from 'react'
import { useMutation, gql } from '@apollo/client'
import styled from 'styled-components' import styled from 'styled-components'
import { Icon } from 'semantic-ui-react' import { Icon } from 'semantic-ui-react'
import { ProtectedImage } from './ProtectedMedia' import { ProtectedImage } from './ProtectedMedia'
import { MediaType } from '../../../__generated__/globalTypes' import { MediaType } from '../../../__generated__/globalTypes'
import {
markMediaFavorite,
markMediaFavoriteVariables,
} from './__generated__/markMediaFavorite'
const markFavoriteMutation = gql`
mutation markMediaFavorite($mediaId: ID!, $favorite: Boolean!) {
favoriteMedia(mediaId: $mediaId, favorite: $favorite) {
id
favorite
}
}
`
const MediaContainer = styled.div` const MediaContainer = styled.div`
flex-grow: 1; flex-grow: 1;
@ -119,26 +105,19 @@ type MediaThumbnailProps = {
height: number height: number
} }
} }
onSelectImage(index: number): void
index: number
active: boolean active: boolean
setPresenting(presenting: boolean): void selectImage(): void
onFavorite?(): void clickPresent(): void
clickFavorite(): void
} }
export const MediaThumbnail = ({ export const MediaThumbnail = ({
media, media,
onSelectImage,
index,
active, active,
setPresenting, selectImage,
onFavorite, clickPresent,
clickFavorite,
}: MediaThumbnailProps) => { }: MediaThumbnailProps) => {
const [markFavorite] = useMutation<
markMediaFavorite,
markMediaFavoriteVariables
>(markFavoriteMutation)
let heartIcon = null let heartIcon = null
if (media.favorite !== undefined) { if (media.favorite !== undefined) {
heartIcon = ( heartIcon = (
@ -147,21 +126,7 @@ export const MediaThumbnail = ({
name={media.favorite ? 'heart' : 'heart outline'} name={media.favorite ? 'heart' : 'heart outline'}
onClick={(event: MouseEvent) => { onClick={(event: MouseEvent) => {
event.stopPropagation() event.stopPropagation()
const favorite = !media.favorite clickFavorite()
markFavorite({
variables: {
mediaId: media.id,
favorite: favorite,
},
optimisticResponse: {
favoriteMedia: {
id: media.id,
favorite: favorite,
__typename: 'Media',
},
},
})
onFavorite && onFavorite()
}} }}
/> />
) )
@ -187,7 +152,7 @@ export const MediaThumbnail = ({
minWidth: `clamp(124px, ${minWidth}px, 100% - 8px)`, minWidth: `clamp(124px, ${minWidth}px, 100% - 8px)`,
}} }}
onClick={() => { onClick={() => {
onSelectImage(index) selectImage()
}} }}
> >
<div <div
@ -203,7 +168,7 @@ export const MediaThumbnail = ({
<HoverIcon <HoverIcon
name="expand" name="expand"
onClick={() => { onClick={() => {
setPresenting(true) clickPresent()
}} }}
/> />
{heartIcon} {heartIcon}

View File

@ -4,10 +4,28 @@ import { Loader } from 'semantic-ui-react'
import { MediaThumbnail, PhotoThumbnail } from './MediaThumbnail' import { MediaThumbnail, PhotoThumbnail } from './MediaThumbnail'
import PresentView from './presentView/PresentView' import PresentView from './presentView/PresentView'
import { SidebarContext } from '../sidebar/Sidebar' import { SidebarContext } from '../sidebar/Sidebar'
import MediaSidebar from '../sidebar/MediaSidebar'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { PresentMediaProps_Media } from './presentView/PresentMedia' import { PresentMediaProps_Media } from './presentView/PresentMedia'
import { sidebarPhoto_media_thumbnail } from '../sidebar/__generated__/sidebarPhoto' import { sidebarPhoto_media_thumbnail } from '../sidebar/__generated__/sidebarPhoto'
import {
PhotoGalleryAction,
PhotoGalleryState,
selectImageAction,
} from './photoGalleryReducer'
import { gql, useMutation } from '@apollo/client'
import {
markMediaFavorite,
markMediaFavoriteVariables,
} from './__generated__/markMediaFavorite'
const markFavoriteMutation = gql`
mutation markMediaFavorite($mediaId: ID!, $favorite: Boolean!) {
favoriteMedia(mediaId: $mediaId, favorite: $favorite) {
id
favorite
}
}
`
const Gallery = styled.div` const Gallery = styled.div`
display: flex; display: flex;
@ -32,37 +50,32 @@ const ClearWrap = styled.div`
clear: both; clear: both;
` `
interface PhotoGalleryProps_Media extends PresentMediaProps_Media { export interface PhotoGalleryProps_Media extends PresentMediaProps_Media {
thumbnail: sidebarPhoto_media_thumbnail | null thumbnail: sidebarPhoto_media_thumbnail | null
favorite?: boolean
} }
type PhotoGalleryProps = { type PhotoGalleryProps = {
loading: boolean loading: boolean
media: PhotoGalleryProps_Media[] mediaState: PhotoGalleryState
activeIndex: number dispatchMedia: React.Dispatch<PhotoGalleryAction>
presenting: boolean
onSelectImage(index: number): void
setPresenting(presenting: boolean): void
nextImage(): void
previousImage(): void
onFavorite?(): void
} }
const PhotoGallery = ({ const PhotoGallery = ({
activeIndex = -1, mediaState,
media,
loading, loading,
onSelectImage, dispatchMedia,
presenting,
setPresenting,
nextImage,
previousImage,
onFavorite,
}: PhotoGalleryProps) => { }: PhotoGalleryProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { updateSidebar } = useContext(SidebarContext) const { updateSidebar } = useContext(SidebarContext)
const activeImage: PhotoGalleryProps_Media | undefined = media[activeIndex] const [markFavorite] = useMutation<
markMediaFavorite,
markMediaFavoriteVariables
>(markFavoriteMutation)
const { media, activeIndex, presenting } = mediaState
let photoElements = [] let photoElements = []
if (media) { if (media) {
@ -73,14 +86,36 @@ const PhotoGallery = ({
<MediaThumbnail <MediaThumbnail
key={media.id} key={media.id}
media={media} media={media}
onSelectImage={index => {
updateSidebar(<MediaSidebar media={media} />)
onSelectImage(index)
}}
onFavorite={onFavorite}
setPresenting={setPresenting}
index={index}
active={active} active={active}
selectImage={() => {
selectImageAction({
index,
mediaState,
dispatchMedia,
updateSidebar,
})
}}
clickFavorite={() => {
markFavorite({
variables: {
mediaId: media.id,
favorite: !media.favorite,
},
optimisticResponse: {
favoriteMedia: {
id: media.id,
favorite: !media.favorite,
__typename: 'Media',
},
},
})
}}
clickPresent={() => {
dispatchMedia({
type: 'setPresenting',
presenting: true,
})
}}
/> />
) )
}) })
@ -100,10 +135,7 @@ const PhotoGallery = ({
<PhotoFiller /> <PhotoFiller />
</Gallery> </Gallery>
{presenting && ( {presenting && (
<PresentView <PresentView mediaState={mediaState} dispatchMedia={dispatchMedia} />
media={activeImage}
{...{ nextImage, previousImage, setPresenting }}
/>
)} )}
</ClearWrap> </ClearWrap>
) )

View File

@ -0,0 +1,91 @@
import { photoGalleryReducer, PhotoGalleryState } from './photoGalleryReducer'
import { MediaType } from '../../../__generated__/globalTypes'
describe('photo gallery reducer', () => {
const defaultState: PhotoGalleryState = {
presenting: false,
activeIndex: 0,
media: [
{
__typename: 'Media',
id: '1',
highRes: null,
thumbnail: null,
type: MediaType.Photo,
},
{
__typename: 'Media',
id: '2',
highRes: null,
thumbnail: null,
type: MediaType.Photo,
},
{
__typename: 'Media',
id: '3',
highRes: null,
thumbnail: null,
type: MediaType.Photo,
},
],
}
test('next image', () => {
expect(photoGalleryReducer(defaultState, { type: 'nextImage' })).toEqual({
...defaultState,
activeIndex: 1,
})
expect(
photoGalleryReducer(
{ ...defaultState, activeIndex: 2 },
{ type: 'nextImage' }
)
).toEqual({
...defaultState,
activeIndex: 0,
})
})
test('previous image', () => {
expect(
photoGalleryReducer(defaultState, { type: 'previousImage' })
).toEqual({
...defaultState,
activeIndex: 2,
})
expect(
photoGalleryReducer(
{ ...defaultState, activeIndex: 2 },
{ type: 'previousImage' }
)
).toEqual({
...defaultState,
activeIndex: 1,
})
})
test('select image', () => {
expect(
photoGalleryReducer(defaultState, { type: 'selectImage', index: 1 })
).toEqual({
...defaultState,
activeIndex: 1,
})
expect(
photoGalleryReducer(defaultState, { type: 'selectImage', index: 100 })
).toEqual({
...defaultState,
activeIndex: 2,
})
expect(
photoGalleryReducer(defaultState, { type: 'selectImage', index: -5 })
).toEqual({
...defaultState,
activeIndex: 0,
})
})
})

View File

@ -0,0 +1,74 @@
import React from 'react'
import { UpdateSidebarFn } from '../sidebar/Sidebar'
import { PhotoGalleryProps_Media } from './PhotoGallery'
import MediaSidebar from '../sidebar/MediaSidebar'
export type PhotoGalleryState = {
presenting: boolean
activeIndex: number
media: PhotoGalleryProps_Media[]
}
export type PhotoGalleryAction =
| { type: 'nextImage' }
| { type: 'previousImage' }
| { type: 'setPresenting'; presenting: boolean }
| { type: 'selectImage'; index: number }
export function photoGalleryReducer(
state: PhotoGalleryState,
action: PhotoGalleryAction
): PhotoGalleryState {
switch (action.type) {
case 'nextImage':
return {
...state,
activeIndex: (state.activeIndex + 1) % state.media.length,
}
case 'previousImage':
if (state.activeIndex <= 0) {
return {
...state,
activeIndex: state.media.length - 1,
}
} else {
return {
...state,
activeIndex: state.activeIndex - 1,
}
}
case 'setPresenting':
return {
...state,
presenting: action.presenting,
}
case 'selectImage':
return {
...state,
activeIndex: Math.max(
0,
Math.min(state.media.length - 1, action.index)
),
}
}
}
export const selectImageAction = ({
index,
mediaState,
dispatchMedia,
updateSidebar,
}: {
index: number
mediaState: PhotoGalleryState
dispatchMedia: React.Dispatch<PhotoGalleryAction>
updateSidebar: UpdateSidebarFn
}) => {
updateSidebar(
<MediaSidebar media={mediaState.media[mediaState.activeIndex]} />
)
dispatchMedia({
type: 'selectImage',
index,
})
}

View File

@ -1,6 +1,7 @@
import React, { useState, useRef, useEffect } from 'react' import React, { useState, useRef, useEffect } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { debounce, DebouncedFn } from '../../../helpers/utils' import { debounce, DebouncedFn } from '../../../helpers/utils'
import { PhotoGalleryAction } from '../photoGalleryReducer'
import ExitIcon from './icons/Exit' import ExitIcon from './icons/Exit'
import NextIcon from './icons/Next' import NextIcon from './icons/Next'
@ -65,16 +66,12 @@ const NavigationButton = styled(OverlayButton)<{ float: 'left' | 'right' }>`
type PresentNavigationOverlayProps = { type PresentNavigationOverlayProps = {
children?: React.ReactChild children?: React.ReactChild
nextImage(): void dispatchMedia: React.Dispatch<PhotoGalleryAction>
previousImage(): void
setPresenting(presenting: boolean): void
} }
const PresentNavigationOverlay = ({ const PresentNavigationOverlay = ({
children, children,
nextImage, dispatchMedia,
previousImage,
setPresenting,
}: PresentNavigationOverlayProps) => { }: PresentNavigationOverlayProps) => {
const [hide, setHide] = useState(true) const [hide, setHide] = useState(true)
const onMouseMove = useRef<null | DebouncedFn<() => void>>(null) const onMouseMove = useRef<null | DebouncedFn<() => void>>(null)
@ -103,20 +100,22 @@ const PresentNavigationOverlay = ({
<NavigationButton <NavigationButton
className={hide ? 'hide' : undefined} className={hide ? 'hide' : undefined}
float="left" float="left"
onClick={() => previousImage()} onClick={() => dispatchMedia({ type: 'previousImage' })}
> >
<PrevIcon /> <PrevIcon />
</NavigationButton> </NavigationButton>
<NavigationButton <NavigationButton
className={hide ? 'hide' : undefined} className={hide ? 'hide' : undefined}
float="right" float="right"
onClick={() => nextImage()} onClick={() => dispatchMedia({ type: 'nextImage' })}
> >
<NextIcon /> <NextIcon />
</NavigationButton> </NavigationButton>
<ExitButton <ExitButton
className={hide ? 'hide' : undefined} className={hide ? 'hide' : undefined}
onClick={() => setPresenting(false)} onClick={() =>
dispatchMedia({ type: 'setPresenting', presenting: false })
}
> >
<ExitIcon /> <ExitIcon />
</ExitButton> </ExitButton>

View File

@ -1,7 +1,8 @@
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import styled, { createGlobalStyle } from 'styled-components' import styled, { createGlobalStyle } from 'styled-components'
import PresentNavigationOverlay from './PresentNavigationOverlay' import PresentNavigationOverlay from './PresentNavigationOverlay'
import PresentMedia, { PresentMediaProps_Media } from './PresentMedia' import PresentMedia from './PresentMedia'
import { PhotoGalleryAction, PhotoGalleryState } from '../photoGalleryReducer'
const StyledContainer = styled.div` const StyledContainer = styled.div`
position: fixed; position: fixed;
@ -21,37 +22,33 @@ const PreventScroll = createGlobalStyle`
` `
type PresentViewProps = { type PresentViewProps = {
media: PresentMediaProps_Media
className?: string className?: string
imageLoaded?(): void imageLoaded?(): void
nextImage(): void mediaState: PhotoGalleryState
previousImage(): void dispatchMedia: React.Dispatch<PhotoGalleryAction>
setPresenting(presenting: boolean): void
} }
const PresentView = ({ const PresentView = ({
className, className,
media,
imageLoaded, imageLoaded,
nextImage, mediaState,
previousImage, dispatchMedia,
setPresenting,
}: PresentViewProps) => { }: PresentViewProps) => {
useEffect(() => { useEffect(() => {
const keyDownEvent = (e: KeyboardEvent) => { const keyDownEvent = (e: KeyboardEvent) => {
if (e.key == 'ArrowRight') { if (e.key == 'ArrowRight') {
nextImage()
e.stopPropagation() e.stopPropagation()
dispatchMedia({ type: 'nextImage' })
} }
if (e.key == 'ArrowLeft') { if (e.key == 'ArrowLeft') {
previousImage()
e.stopPropagation() e.stopPropagation()
dispatchMedia({ type: 'previousImage' })
} }
if (e.key == 'Escape') { if (e.key == 'Escape') {
setPresenting(false)
e.stopPropagation() e.stopPropagation()
dispatchMedia({ type: 'setPresenting', presenting: false })
} }
} }
@ -65,10 +62,11 @@ const PresentView = ({
return ( return (
<StyledContainer {...className}> <StyledContainer {...className}>
<PreventScroll /> <PreventScroll />
<PresentNavigationOverlay <PresentNavigationOverlay dispatchMedia={dispatchMedia}>
{...{ nextImage, previousImage, setPresenting }} <PresentMedia
> media={mediaState.media[mediaState.activeIndex]}
<PresentMedia media={media} imageLoaded={imageLoaded} /> imageLoaded={imageLoaded}
/>
</PresentNavigationOverlay> </PresentNavigationOverlay>
</StyledContainer> </StyledContainer>
) )

View File

@ -52,9 +52,10 @@
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
"typeRoots": [ "typeRoots": [
"node_modules/@types",
"./src/@types/" "./src/@types/"
] /* List of folders to include type definitions from. */, ] /* List of folders to include type definitions from. */,
// "types": [], /* Type declaration files to be included in compilation. */ "types": ["jest"], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */