Skip to content

Commit

Permalink
Added background image loading handle
Browse files Browse the repository at this point in the history
  • Loading branch information
nullhook committed Dec 1, 2022
1 parent a7c826e commit bb8cf67
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 132 deletions.
5 changes: 3 additions & 2 deletions components/brave_welcome_ui/api/web_animation_player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ class WebAnimationPlayer {
this.timingOption = timingOption
}

to (element: Element | null, keyframeEffectOption: PropertyIndexedKeyframes) {
const kF = new KeyframeEffect(element, keyframeEffectOption, this.timingOption)
to (element: Element | null, keyFrame: PropertyIndexedKeyframes, keyFrameOption?: OptionalEffectTiming) {
const kFOptions = { ...this.timingOption, ...keyFrameOption }
const kF = new KeyframeEffect(element, keyFrame, kFOptions)
const animation = new Animation(kF)
this.animations.push(animation)
return this
Expand Down
3 changes: 3 additions & 0 deletions components/brave_welcome_ui/brave_welcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

body {
background: black;
height: 100vh;
margin: 0;
padding: 0;
}
</style>
</head>
Expand Down
92 changes: 61 additions & 31 deletions components/brave_welcome_ui/components/background/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,31 @@

import * as React from 'react'
import * as S from './style'
import classnames from '$web-common/classnames'

import WebAnimationPlayer from '../../api/web_animation_player'
import DataContext from '../../state/context'
import { useShouldPlayAnimations } from '../../state/hooks'

import Stars01 from '../svg/stars01'
import Stars02 from '../svg/stars02'
import Stars03 from '../svg/stars03'
import Stars04 from '../svg/stars04'
import fullCompositeBgUrl from '../../assets/[email protected]'
import skyBgUrl from '../../assets/sky.webp'

interface BackgroundProps {
children?: JSX.Element
static: boolean
onLoad?: () => void
}

function AnimatedBackground (props: { children?: JSX.Element }) {
function Background (props: BackgroundProps) {
const ref = React.useRef<HTMLDivElement>(null)
const { setScenes } = React.useContext(DataContext)
const [hasLoaded, setHasLoaded] = React.useState(false)
const isReadyForAnimation = hasLoaded && !props.static
const shouldPlayAnimations = useShouldPlayAnimations()

React.useEffect(() => {
if (!ref.current) return
Expand Down Expand Up @@ -55,43 +63,65 @@ function AnimatedBackground (props: { children?: JSX.Element }) {
.to(stars04, { transform: 'scale(1.5)' })

setScenes({ s1, s2 })
}, [])
}, [isReadyForAnimation])

React.useEffect(() => {
if (!ref.current) return

const s1 = new WebAnimationPlayer()
const starsContainer = ref.current.querySelector('.stars-container')
const hillsContainer = ref.current.querySelector('.hills-container')

s1.to(starsContainer, { opacity: 1 }, { delay: 250 })
.to(hillsContainer, { opacity: 1 }, { delay: 250 })

const lastAnimationEl = s1.animations[s1.animations.length - 1]
lastAnimationEl.addEventListener('finish', () => props.onLoad?.())

s1.play()
}, [isReadyForAnimation])

const handleImgLoad = () => {
setHasLoaded(true)

// When animations are disabled, we trigger onLoad instantly
if (!shouldPlayAnimations) {
props.onLoad?.()
}
}

return (
<S.Box ref={ref}>
<div className="stars-container">
<Stars01 />
<Stars02 />
<Stars03 />
<Stars04 />
</div>
<S.Box ref={isReadyForAnimation ? ref : null}>
{isReadyForAnimation && (
<div className="stars-container">
<Stars01 />
<Stars02 />
<Stars03 />
<Stars04 />
</div>
)}
<div className="content-box">
{props.children}
</div>
<div className="sky" />
<div className="hills-container">
<div className="hills-base hills03"></div>
<div className="hills-base hills02"></div>
<div className="hills-base hills01"></div>
<div className="pyramid"></div>
</div>
<img
// We animate the background image via CSS only.
className={classnames({
'background-img': true,
'is-visible': hasLoaded
})}
src={!props.static ? skyBgUrl : fullCompositeBgUrl}
onLoad={handleImgLoad}
/>
{isReadyForAnimation && (
<div className="hills-container">
<div className="hills-base hills03"></div>
<div className="hills-base hills02"></div>
<div className="hills-base hills01"></div>
<div className="pyramid"></div>
</div>
)}
</S.Box>
)
}

function Background (props: BackgroundProps) {
if (!props.static) {
return (<AnimatedBackground>
{props.children}
</AnimatedBackground>
)
}

return (
<S.StaticBackground>
{props.children}
</S.StaticBackground>
)
}

export default Background
102 changes: 48 additions & 54 deletions components/brave_welcome_ui/components/background/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,76 @@

import styled from 'styled-components'

import skyeBgUrl from '../../assets/sky.webp'
import hillBgUrl from '../../assets/hill.webp'
import pyramidBgUrl from '../../assets/pyramid.webp'
import backgroundUrl2x from '../../assets/[email protected]'

export const Box = styled.div`
.content-box {
position: fixed;
width: 100%;
height: 100vh;
height: 100%;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
}
.sky {
.background-img {
position: fixed;
width: 100vw;
height: 100vh;
background: url(${skyeBgUrl}) no-repeat;
background-size: cover;
width: 100%;
height: 100%;
z-index: 1;
object-fit: cover;
opacity: 0;
transition: opacity .2s ease-in;
&.is-visible {
opacity: 1;
}
}
.hills-container {
position: fixed;
width: 100vw;
height: 100vh;
height: 100%;
z-index: 2;
opacity: 0;
}
.stars-container {
position: fixed;
width: 100vw;
height: 100%;
z-index: 50;
opacity: 0;
svg {
width: 100%;
height: auto;
position: absolute;
transform-origin: center;
}
.stars01 {
bottom: 0;
transform: scale(1.14);
filter: blur(3px);
}
.stars02 {
top: 10%;
}
.stars03 {
top: 15%;
}
.stars04 {
top: 30%;
transform: scale(0.8);
opacity: 0;
}
}
.hills-base {
Expand Down Expand Up @@ -77,48 +115,4 @@ export const Box = styled.div`
z-index: 1;
transform: translateX(20%);
}
.stars-container {
position: fixed;
width: 100vw;
height: 100vh;
z-index: 50;
svg {
width: 100%;
height: auto;
position: absolute;
transform-origin: center;
}
.stars01 {
bottom: 0;
transform: scale(1.14);
filter: blur(3px);
}
.stars02 {
top: 10%;
}
.stars03 {
top: 15%;
}
.stars04 {
top: 30%;
transform: scale(0.8);
opacity: 0;
}
}
`

export const StaticBackground = styled.div`
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
background: url(${backgroundUrl2x}) no-repeat center center;
background-size: cover;
`
79 changes: 48 additions & 31 deletions components/brave_welcome_ui/components/welcome/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
// you can obtain one at https://mozilla.org/MPL/2.0/.

import * as React from 'react'
import { getLocale } from '$web-common/locale'
import classnames from '$web-common/classnames'

import * as S from './style'
import DataContext from '../../state/context'
import { useShouldPlayAnimations } from '../../state/hooks'

import { WelcomeBrowserProxyImpl, DefaultBrowserBrowserProxyImpl } from '../../api/welcome_browser_proxy'
import WebAnimationPlayer from '../../api/web_animation_player'
import DataContext from '../../state/context'
import { ViewType } from '../../state/component_types'
import { useShouldPlayAnimations } from '../../state/hooks'

import Button from '$web-components/button'
import { getLocale } from '$web-common/locale'
import braveLogoUrl from '../../assets/[email protected]'

function Welcome () {
Expand All @@ -36,44 +40,57 @@ function Welcome () {
if (!ref.current) return
if (!shouldPlayAnimations) return

const logoAnim: Animation = ref.current.animate({
transform: 'translateY(-20px)',
filter: 'drop-shadow(7px 2px 5px rgba(14, 1, 41, 0.2)) drop-shadow(14px 3px 10px rgba(32, 5, 89, 0.3)) drop-shadow(20px 3px 15px rgba(37, 7, 87, 0.2)) drop-shadow(25px 5px 30px rgba(25, 3, 73, 0.1)) drop-shadow(50px 4px 50px rgba(19, 3, 40, 0.1))'
}, { duration: 1000, fill: 'forwards', easing: 'ease-out' })
const logoBoxEl = ref.current.querySelector('.view-logo-box')
const backdropEl = ref.current.querySelector('.view-backdrop')
const contentEl = ref.current.querySelector('.view-content')

const s1 = new WebAnimationPlayer()

s1.to(logoBoxEl, {
transform: 'translateY(-20px)',
filter: 'drop-shadow(7px 2px 5px rgba(14, 1, 41, 0.2)) drop-shadow(14px 3px 10px rgba(32, 5, 89, 0.3)) drop-shadow(20px 3px 15px rgba(37, 7, 87, 0.2)) drop-shadow(25px 5px 30px rgba(25, 3, 73, 0.1)) drop-shadow(50px 4px 50px rgba(19, 3, 40, 0.1))'
}, { fill: 'forwards', easing: 'ease-out' })
.to(backdropEl, { scale: 1, opacity: 1 }, { duration: 250, delay: 200, easing: 'ease-out' })
.to(contentEl, { transform: 'translateY(0px)', opacity: 1 }, { duration: 250, delay: 200, easing: 'ease-out' })

s1.play()

return () => {
logoAnim.finish()
logoAnim.cancel()
s1.finish()
s1.cancel()
}
}, [])

return (
<S.Box>
<div ref={ref} className="brave-logo-box">
<S.Box ref={shouldPlayAnimations ? ref : null}>
<div className="view-logo-box">
<img src={braveLogoUrl} />
</div>
<div className="view-header-box">
<div className="view-details">
<h1 className="view-title">{getLocale('braveWelcomeTitle')}</h1>
<p className="view-desc">{getLocale('braveWelcomeDesc')}</p>
<div className={classnames({ 'view-content': true, 'initial': shouldPlayAnimations })}>
<div className="view-header-box">
<div className="view-details">
<h1 className="view-title">{getLocale('braveWelcomeTitle')}</h1>
<p className="view-desc">{getLocale('braveWelcomeDesc')}</p>
</div>
</div>
<S.ActionBox>
<Button
isPrimary={true}
onClick={handleSetAsDefaultBrowser}
scale="jumbo"
>
{getLocale('braveWelcomeSetDefaultButtonLabel')}
</Button>
<Button
isTertiary={true}
onClick={handleSkip}
scale="jumbo"
>
{getLocale('braveWelcomeSkipButtonLabel')}
</Button>
</S.ActionBox>
</div>
<S.ActionBox>
<Button
isPrimary={true}
onClick={handleSetAsDefaultBrowser}
scale="jumbo"
>
{getLocale('braveWelcomeSetDefaultButtonLabel')}
</Button>
<Button
isTertiary={true}
onClick={handleSkip}
scale="jumbo"
>
{getLocale('braveWelcomeSkipButtonLabel')}
</Button>
</S.ActionBox>
<div className={classnames({ 'view-backdrop': true, 'initial': shouldPlayAnimations })} />
</S.Box>
)
}
Expand Down
Loading

0 comments on commit bb8cf67

Please sign in to comment.