Add images and wow styles

This commit is contained in:
obergodmar
2020-06-23 01:53:34 +03:00
parent 00e142bf09
commit 98a307f2cc
24 changed files with 259 additions and 21 deletions
+44 -2
View File
@@ -1,13 +1,19 @@
import * as React from 'react' import * as React from 'react'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { PanelComponent } from '../components' import { PanelComponent, PreviewComponent, ViewComponent } from '../components'
import places from '../assets'
import './style.scss' import './style.scss'
const delay = () => new Promise(resolve => setTimeout(resolve, 800))
export default function App() { export default function App() {
const [isLoading, setLoading] = useState(false)
const [isLeftPanelShown, setLeftPanelShown] = useState(false) const [isLeftPanelShown, setLeftPanelShown] = useState(false)
const [isBottomPanelShown, setBottomPanelShown] = useState(true) const [isBottomPanelShown, setBottomPanelShown] = useState(false)
const [activePlace, setActivePlace] = useState(0)
const [activeView, setActiveView] = useState(0)
const handleHideLeftPanel = useCallback(() => { const handleHideLeftPanel = useCallback(() => {
setBottomPanelShown(false) setBottomPanelShown(false)
@@ -19,18 +25,54 @@ export default function App() {
setBottomPanelShown(!isBottomPanelShown) setBottomPanelShown(!isBottomPanelShown)
}, [isBottomPanelShown]) }, [isBottomPanelShown])
const handleLeftPreviewClick = useCallback((value: number) => {
setActivePlace(value)
}, [])
const handleBottomPreviewClick = (value: number) => {
if (isLoading) {
return
}
setActiveView(value)
setLoading(true)
delay().then(() => {
setLoading(false)
})
}
return ( return (
<div className='main'> <div className='main'>
<ViewComponent src={places[activePlace].view[activeView]}/>
<PanelComponent <PanelComponent
orientation='left' orientation='left'
isShown={isLeftPanelShown} isShown={isLeftPanelShown}
setShown={handleHideLeftPanel} setShown={handleHideLeftPanel}
>
{places.map((place, index) => (
<PreviewComponent
isLoading={isLoading}
key={index}
value={index}
handleChange={handleLeftPreviewClick}
src={place.preview[0]}
/> />
))}
</PanelComponent>
<PanelComponent <PanelComponent
orientation='bottom' orientation='bottom'
isShown={isBottomPanelShown} isShown={isBottomPanelShown}
setShown={handleHideBottomPanel} setShown={handleHideBottomPanel}
>
{places[activePlace].preview.map((preview, index) => (
<PreviewComponent
isLoading={isLoading}
key={index}
value={index}
handleChange={handleBottomPreviewClick}
src={preview}
/> />
))}
</PanelComponent>
</div> </div>
) )
} }
+8 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7
View File
@@ -0,0 +1,7 @@
import preview from './preview'
import view from './view'
export default {
preview,
view
}
@@ -0,0 +1,13 @@
import StormwindPark1 from './stormwind-park-1.jpg'
import StormwindPark2 from './stormwind-park-2.jpg'
import StormwindPark3 from './stormwind-park-3.jpg'
import StormwindPark4 from './stormwind-park-4.jpg'
import StormwindPark5 from './stormwind-park-5.jpg'
export default [
StormwindPark1,
StormwindPark2,
StormwindPark3,
StormwindPark4,
StormwindPark5
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

+13
View File
@@ -0,0 +1,13 @@
import StormwindPark1 from './stormwind-park-1.jpg'
import StormwindPark2 from './stormwind-park-2.jpg'
import StormwindPark3 from './stormwind-park-3.jpg'
import StormwindPark4 from './stormwind-park-4.jpg'
import StormwindPark5 from './stormwind-park-5.jpg'
export default [
StormwindPark1,
StormwindPark2,
StormwindPark3,
StormwindPark4,
StormwindPark5
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 KiB

+1
View File
@@ -1,2 +1,3 @@
export { ViewComponent } from './view-component/view-component' export { ViewComponent } from './view-component/view-component'
export { PanelComponent } from './panel-component/panel-component' export { PanelComponent } from './panel-component/panel-component'
export { PreviewComponent } from './preview-component/preview-component'
@@ -1,10 +1,20 @@
@import "../../app/style";
.panel { .panel {
z-index: 2;
display: flex; display: flex;
justify-content: flex-start;
align-items: center;
border: none;
position: absolute; position: absolute;
height: 0; height: 220px;
width: 0; width: 360px;
background-image: $panelBackground;
background-repeat: repeat;
button { button {
z-index: 3;
cursor: pointer;
position: absolute; position: absolute;
width: 10px; width: 10px;
height: 10px; height: 10px;
@@ -22,10 +32,19 @@
} }
&--bottom { &--bottom {
bottom: 0; bottom: -220px;
border: none;
width: 100%; width: 100%;
transition: height 0.5s; transition: bottom 0.5s;
.panel-border {
position: absolute;
z-index: 3;
top: -10px;
min-width: 100%;
background-image: $borderRight;
background-repeat: repeat;
height: 16px;
}
button { button {
left: 50%; left: 50%;
@@ -35,8 +54,7 @@
} }
&--shown { &--shown {
border-top: 2px solid var(--foreground); bottom: 0;
height: 360px;
button { button {
height: 25px; height: 25px;
@@ -46,10 +64,20 @@
} }
&--left { &--left {
left: 0; left: -360px;
border: none; flex-direction: column;
height: 100%; height: 100%;
transition: width 0.5s; transition: left 0.5s;
.panel-border {
position: absolute;
z-index: 3;
right: -8px;
min-height: 100%;
background-image: $borderTop;
background-repeat: repeat;
width: 16px;
}
button { button {
top: 50%; top: 50%;
@@ -59,8 +87,7 @@
} }
&--shown { &--shown {
border-right: 2px solid var(--foreground); left: 0;
width: 360px;
button { button {
width: 25px; width: 25px;
@@ -1,5 +1,5 @@
import * as React from 'react' import * as React from 'react'
import { useCallback } from 'react' import { useCallback, useEffect, useState } from 'react'
import './panel-component.scss' import './panel-component.scss'
@@ -7,9 +7,15 @@ interface Props {
orientation: 'bottom' | 'left' orientation: 'bottom' | 'left'
isShown: boolean isShown: boolean
setShown: () => void setShown: () => void
children: React.ReactNode
} }
export const PanelComponent = ({orientation, isShown, setShown}: Props) => { export const PanelComponent = ({orientation, isShown, setShown, children}: Props) => {
const [isRendered, setRendered] = useState(false)
useEffect(() => {
setRendered(isShown)
}, [isShown])
const handleClick = useCallback((event) => { const handleClick = useCallback((event) => {
event.preventDefault() event.preventDefault()
@@ -20,6 +26,8 @@ export const PanelComponent = ({orientation, isShown, setShown}: Props) => {
<div <div
className={`panel panel--${orientation} ${isShown ? `panel--${orientation}--shown` : ''}`} className={`panel panel--${orientation} ${isShown ? `panel--${orientation}--shown` : ''}`}
> >
<div className='panel-border'/>
{isRendered && children}
<button onClick={handleClick}/> <button onClick={handleClick}/>
</div> </div>
) )
@@ -0,0 +1,18 @@
@import "../../app/style";
.preview {
z-index: 4;
cursor: pointer;
min-width: 320px;
min-height: 180px;
margin: 5px;
border: 10px double var(--foreground);
border-image: $border 12 12 11 12;
border-image-width: 10px;
border-image-outset: 5px;
border-image-repeat: stretch stretch;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
transition: opacity 800ms ease-in-out;
}
@@ -0,0 +1,43 @@
import * as React from 'react'
import { useMemo, useState } from 'react'
import { Plug } from '../../assets'
import './preview-component.scss'
interface Props {
isLoading: boolean
src: string
value: number
handleChange: (value: number) => void
}
export const PreviewComponent = ({src, value, handleChange, isLoading}: Props) => {
const [isLoaded, setLoaded] = useState(false)
const image = useMemo(() => {
setLoaded(false)
const img = new Image(320, 180)
img.src = src
img.onload = () => {
setLoaded(true)
}
return img
}, [src])
const handleClick = () => {
handleChange(value)
}
return (
<div
onClick={handleClick}
style={{
backgroundImage: `url(${isLoaded ? image.src : Plug})`,
backgroundSize: `${isLoaded ? '320px 180px' : '90px 90px'}`,
opacity: `${isLoading ? '0.4' : '1'}`
}}
className='preview'
/>
)
}
PreviewComponent.displayName = 'PreviewComponent'
@@ -0,0 +1,21 @@
.view {
z-index: 1;
position: absolute;
top: 0;
left: 0;
min-width: 100vw;
min-height: 100vh;
background-position: center;
transition: background-image 500ms ease-in;
animation: pulse 10s infinite;
animation-direction: alternate;
}
@keyframes pulse {
0% {
transform: scale(1.02);
}
100% {
transform: scale(1);
}
}
@@ -1,8 +1,37 @@
import * as React from 'react' import * as React from 'react'
import { useEffect, useMemo, useState } from 'react'
import { Background } from '../../assets'
import './view-component.scss'
interface Props {
src: string
}
export const ViewComponent = ({src}: Props) => {
const [imageSrc, setImageSrc] = useState(Background)
const isImage = useMemo(() => imageSrc !== Background, [imageSrc])
useEffect(() => {
setTimeout(() => {
const image = new Image()
image.src = src
image.onload = () => {
setImageSrc(src)
}
}, 500)
}, [src])
export const ViewComponent = () => {
return ( return (
<div/> <div
className='view'
style={{
backgroundImage: `url(${imageSrc})`,
backgroundRepeat: `${isImage ? 'no-repeat' : 'repeat'}`,
backgroundSize: `${isImage ? 'cover' : '256px'}`
}}
/>
) )
} }
+1
View File
@@ -14,6 +14,7 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"module": "esnext", "module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"downlevelIteration": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"noEmit": true, "noEmit": true,