このコミットが含まれているのは:
@@ -2753,26 +2753,13 @@ const GekanatorBackdrop: FC<{
|
|||||||
nextThumbnails)
|
nextThumbnails)
|
||||||
const [flipVisualSeed, setFlipVisualSeed] = useState (visualSeed)
|
const [flipVisualSeed, setFlipVisualSeed] = useState (visualSeed)
|
||||||
const [isFlippingTiles, setIsFlippingTiles] = useState (false)
|
const [isFlippingTiles, setIsFlippingTiles] = useState (false)
|
||||||
const [isCrossfading, setIsCrossfading] = useState (false)
|
|
||||||
|
|
||||||
const isLeavingGuessBackdrop = displayedBackdropMode === 'guess' && backdropMode !== 'guess'
|
const renderedSettings = settingsForMode (displayedBackdropMode)
|
||||||
|
|
||||||
const renderBackdropMode = isLeavingGuessBackdrop ? backdropMode : displayedBackdropMode
|
|
||||||
|
|
||||||
const renderWinningRunCount = (isLeavingGuessBackdrop
|
|
||||||
? winningRunQuestionCount
|
|
||||||
: displayedWinningRunCount)
|
|
||||||
|
|
||||||
const renderThumbnails = isLeavingGuessBackdrop ? nextThumbnails : displayedThumbnails
|
|
||||||
|
|
||||||
const renderIsCrossfading = isCrossfading && !(isLeavingGuessBackdrop)
|
|
||||||
|
|
||||||
const renderedSettings = settingsForMode (renderBackdropMode)
|
|
||||||
const renderedTileCount = renderedSettings.columns * renderedSettings.rows
|
const renderedTileCount = renderedSettings.columns * renderedSettings.rows
|
||||||
const renderedScale = scaleForMode (renderBackdropMode, renderWinningRunCount)
|
const renderedScale = scaleForMode (displayedBackdropMode, displayedWinningRunCount)
|
||||||
|
|
||||||
const isGuessPresentation = backdropMode === 'guess'
|
const isGuessPresentation =
|
||||||
const crossfadeDuration = motionMode === 'calm' ? .95 : .75
|
backdropMode === 'guess' || displayedBackdropMode === 'guess'
|
||||||
|
|
||||||
useEffect (() => {
|
useEffect (() => {
|
||||||
guessAnimationControlsRef.current.forEach (control => control.stop ())
|
guessAnimationControlsRef.current.forEach (control => control.stop ())
|
||||||
@@ -2866,7 +2853,6 @@ const GekanatorBackdrop: FC<{
|
|||||||
{
|
{
|
||||||
applyDirection ()
|
applyDirection ()
|
||||||
setIsFlippingTiles (false)
|
setIsFlippingTiles (false)
|
||||||
setIsCrossfading (false)
|
|
||||||
setFlipVisualSeed (visualSeed)
|
setFlipVisualSeed (visualSeed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -2874,7 +2860,6 @@ const GekanatorBackdrop: FC<{
|
|||||||
if (backdropMode === 'guess' && guessThumbnail)
|
if (backdropMode === 'guess' && guessThumbnail)
|
||||||
{
|
{
|
||||||
setIsFlippingTiles (false)
|
setIsFlippingTiles (false)
|
||||||
setIsCrossfading (false)
|
|
||||||
setDisplayedBackdropMode ('guess')
|
setDisplayedBackdropMode ('guess')
|
||||||
setDisplayedWinningRunCount (winningRunQuestionCount)
|
setDisplayedWinningRunCount (winningRunQuestionCount)
|
||||||
setDisplayedThumbnails (nextThumbnails)
|
setDisplayedThumbnails (nextThumbnails)
|
||||||
@@ -2894,7 +2879,6 @@ const GekanatorBackdrop: FC<{
|
|||||||
setFromThumbnails (nextThumbnails)
|
setFromThumbnails (nextThumbnails)
|
||||||
setToThumbnails (nextThumbnails)
|
setToThumbnails (nextThumbnails)
|
||||||
setIsFlippingTiles (false)
|
setIsFlippingTiles (false)
|
||||||
setIsCrossfading (false)
|
|
||||||
setFlipVisualSeed (visualSeed)
|
setFlipVisualSeed (visualSeed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -2903,23 +2887,6 @@ const GekanatorBackdrop: FC<{
|
|||||||
{
|
{
|
||||||
applyDirection ()
|
applyDirection ()
|
||||||
setIsFlippingTiles (false)
|
setIsFlippingTiles (false)
|
||||||
setIsCrossfading (false)
|
|
||||||
setFlipVisualSeed (visualSeed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displayedBackdropMode === 'guess' && backdropMode !== 'guess')
|
|
||||||
{
|
|
||||||
applyDirection ()
|
|
||||||
x.set (0)
|
|
||||||
y.set (0)
|
|
||||||
setIsFlippingTiles (false)
|
|
||||||
setIsCrossfading (false)
|
|
||||||
setDisplayedBackdropMode (backdropMode)
|
|
||||||
setDisplayedWinningRunCount (winningRunQuestionCount)
|
|
||||||
setDisplayedThumbnails (nextThumbnails)
|
|
||||||
setFromThumbnails (nextThumbnails)
|
|
||||||
setToThumbnails (nextThumbnails)
|
|
||||||
setFlipVisualSeed (visualSeed)
|
setFlipVisualSeed (visualSeed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -2942,10 +2909,7 @@ const GekanatorBackdrop: FC<{
|
|||||||
|
|
||||||
setFromThumbnails (currentThumbnails)
|
setFromThumbnails (currentThumbnails)
|
||||||
setToThumbnails (nextThumbnails)
|
setToThumbnails (nextThumbnails)
|
||||||
const shouldCrossfade =
|
setIsFlippingTiles (true)
|
||||||
displayedBackdropMode === 'winning_run' && backdropMode === 'normal'
|
|
||||||
setIsCrossfading (shouldCrossfade)
|
|
||||||
setIsFlippingTiles (!(shouldCrossfade))
|
|
||||||
|
|
||||||
flipTimerRef.current = window.setTimeout (() => {
|
flipTimerRef.current = window.setTimeout (() => {
|
||||||
setDisplayedBackdropMode (backdropMode)
|
setDisplayedBackdropMode (backdropMode)
|
||||||
@@ -2954,11 +2918,10 @@ const GekanatorBackdrop: FC<{
|
|||||||
setFromThumbnails (nextThumbnails)
|
setFromThumbnails (nextThumbnails)
|
||||||
setToThumbnails (nextThumbnails)
|
setToThumbnails (nextThumbnails)
|
||||||
setIsFlippingTiles (false)
|
setIsFlippingTiles (false)
|
||||||
setIsCrossfading (false)
|
|
||||||
applyDirection ()
|
applyDirection ()
|
||||||
setFlipVisualSeed (visualSeed)
|
setFlipVisualSeed (visualSeed)
|
||||||
flipTimerRef.current = null
|
flipTimerRef.current = null
|
||||||
}, (shouldCrossfade ? crossfadeDuration : tileFlipDuration) * 1000)
|
}, tileFlipDuration * 1000)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (flipTimerRef.current !== null)
|
if (flipTimerRef.current !== null)
|
||||||
@@ -2978,126 +2941,10 @@ const GekanatorBackdrop: FC<{
|
|||||||
visualSeed,
|
visualSeed,
|
||||||
activeDirection,
|
activeDirection,
|
||||||
winningRunQuestionCount,
|
winningRunQuestionCount,
|
||||||
crossfadeDuration,
|
|
||||||
tileFlipDuration,
|
tileFlipDuration,
|
||||||
x,
|
x,
|
||||||
y])
|
y])
|
||||||
|
|
||||||
const renderTileSet = (
|
|
||||||
{ mode,
|
|
||||||
thumbnails,
|
|
||||||
settings,
|
|
||||||
tileCount,
|
|
||||||
scale,
|
|
||||||
opacity,
|
|
||||||
withFlip }: { mode: 'normal' | 'winning_run' | 'guess'
|
|
||||||
thumbnails: string[]
|
|
||||||
settings: { columns: number; rows: number; opacity: number }
|
|
||||||
tileCount: number
|
|
||||||
scale: number
|
|
||||||
opacity?: number
|
|
||||||
withFlip?: boolean }) => {
|
|
||||||
const guessModeFlg = mode === 'guess'
|
|
||||||
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
className="absolute inset-0"
|
|
||||||
initial={guessModeFlg
|
|
||||||
? false
|
|
||||||
: (opacity == null
|
|
||||||
? undefined
|
|
||||||
: { opacity: opacity === 0 ? 1 : 0, scale, x: '0%', y: '0%' })}
|
|
||||||
animate={{ opacity: opacity ?? 1,
|
|
||||||
scale,
|
|
||||||
x: guessModeFlg ? guessFocusOffset.x : '0%',
|
|
||||||
y: guessModeFlg ? guessFocusOffset.y : '0%' }}
|
|
||||||
transition={guessModeFlg
|
|
||||||
? { duration: 0 }
|
|
||||||
: (mode === 'winning_run'
|
|
||||||
? { duration: crossfadeDuration, ease: [.16, 1, .3, 1] }
|
|
||||||
: { duration: .2 })}>
|
|
||||||
{Array.from ({ length: 9 }, (_, duplicate) => {
|
|
||||||
const column = duplicate % 3
|
|
||||||
const row = Math.floor (duplicate / 3)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
key={`${ mode }:${ duplicate }`}
|
|
||||||
className="absolute grid overflow-hidden"
|
|
||||||
layout={mode === 'winning_run'}
|
|
||||||
style={{
|
|
||||||
left: `${ column * 33.333333 }%`,
|
|
||||||
top: `${ row * 33.333333 }%`,
|
|
||||||
width: '33.333333%',
|
|
||||||
height: '33.333333%',
|
|
||||||
gridTemplateColumns:
|
|
||||||
`repeat(${ settings.columns }, minmax(0, 1fr))`,
|
|
||||||
gridTemplateRows:
|
|
||||||
`repeat(${ settings.rows }, minmax(0, 1fr))` }}
|
|
||||||
transition={{ duration: tileFlipDuration, ease: 'easeInOut' }}>
|
|
||||||
{Array.from ({ length: tileCount }, (_, index) => {
|
|
||||||
const currentThumbnail =
|
|
||||||
thumbnails[index % Math.max (thumbnails.length, 1)]
|
|
||||||
const frontThumbnail =
|
|
||||||
withFlip
|
|
||||||
? fromThumbnails[index % Math.max (fromThumbnails.length, 1)]
|
|
||||||
: currentThumbnail
|
|
||||||
const backThumbnail =
|
|
||||||
withFlip
|
|
||||||
? toThumbnails[index % Math.max (toThumbnails.length, 1)]
|
|
||||||
: currentThumbnail
|
|
||||||
const thumbnail = currentThumbnail
|
|
||||||
if (!(thumbnail) || !(frontThumbnail) || !(backThumbnail))
|
|
||||||
return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
key={`${ mode }:${ duplicate }:${ index }`}
|
|
||||||
className="relative overflow-hidden"
|
|
||||||
layout={mode === 'winning_run'}
|
|
||||||
transition={{ duration: tileFlipDuration, ease: 'easeInOut' }}
|
|
||||||
style={{ perspective: 1600 }}>
|
|
||||||
{(mode !== 'normal' || !(withFlip))
|
|
||||||
? (
|
|
||||||
<img
|
|
||||||
src={['intro', 'end'].includes (phase)
|
|
||||||
? mascotAsset
|
|
||||||
: thumbnail}
|
|
||||||
alt=""
|
|
||||||
className="absolute inset-0 h-full w-full object-cover"
|
|
||||||
style={{ opacity: settings.opacity }}/>)
|
|
||||||
: (
|
|
||||||
<motion.div
|
|
||||||
className="absolute inset-0"
|
|
||||||
initial={{ rotateY: 0 }}
|
|
||||||
animate={{ rotateY: 180 }}
|
|
||||||
transition={{
|
|
||||||
duration: tileFlipDuration,
|
|
||||||
ease: 'easeInOut' }}
|
|
||||||
style={{ transformStyle: 'preserve-3d' }}>
|
|
||||||
<img
|
|
||||||
src={backThumbnail}
|
|
||||||
alt=""
|
|
||||||
className="absolute inset-0 h-full w-full object-cover"
|
|
||||||
style={{
|
|
||||||
backfaceVisibility: 'hidden',
|
|
||||||
opacity: settings.opacity,
|
|
||||||
transform: 'rotateY(180deg)' }}/>
|
|
||||||
<img
|
|
||||||
src={frontThumbnail}
|
|
||||||
alt=""
|
|
||||||
className="absolute inset-0 h-full w-full object-cover"
|
|
||||||
style={{
|
|
||||||
backfaceVisibility: 'hidden',
|
|
||||||
opacity: settings.opacity }}/>
|
|
||||||
</motion.div>)}
|
|
||||||
</motion.div>)
|
|
||||||
})}
|
|
||||||
</motion.div>)
|
|
||||||
})}
|
|
||||||
</motion.div>)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motionMode === 'off' || nextThumbnails.length === 0)
|
if (motionMode === 'off' || nextThumbnails.length === 0)
|
||||||
return (
|
return (
|
||||||
<div className="absolute inset-0 bg-gradient-to-br from-yellow-50 via-white
|
<div className="absolute inset-0 bg-gradient-to-br from-yellow-50 via-white
|
||||||
@@ -3113,34 +2960,99 @@ const GekanatorBackdrop: FC<{
|
|||||||
width: 'calc(max(100vw, 100vh) * 3)',
|
width: 'calc(max(100vw, 100vh) * 3)',
|
||||||
height: 'calc(max(100vw, 100vh) * 3)' }}>
|
height: 'calc(max(100vw, 100vh) * 3)' }}>
|
||||||
<motion.div
|
<motion.div
|
||||||
className="relative h-full w-full">
|
className="relative h-full w-full"
|
||||||
{renderIsCrossfading
|
animate={{ scale: renderedScale,
|
||||||
|
x: displayedBackdropMode === 'guess' ? guessFocusOffset.x : '0%',
|
||||||
|
y: displayedBackdropMode === 'guess' ? guessFocusOffset.y : '0%' }}
|
||||||
|
transition={(displayedBackdropMode === 'winning_run'
|
||||||
|
|| displayedBackdropMode === 'guess')
|
||||||
|
? { duration: motionMode === 'calm' ? .95 : .75,
|
||||||
|
ease: [.16, 1, .3, 1] }
|
||||||
|
: { duration: .2 }}>
|
||||||
|
{Array.from ({ length: 9 }, (_, duplicate) => {
|
||||||
|
const column = duplicate % 3
|
||||||
|
const row = Math.floor (duplicate / 3)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={duplicate}
|
||||||
|
className="absolute grid overflow-hidden"
|
||||||
|
layout={displayedBackdropMode !== 'normal'}
|
||||||
|
style={{
|
||||||
|
left: `${ column * 33.333333 }%`,
|
||||||
|
top: `${ row * 33.333333 }%`,
|
||||||
|
width: '33.333333%',
|
||||||
|
height: '33.333333%',
|
||||||
|
gridTemplateColumns:
|
||||||
|
`repeat(${ renderedSettings.columns }, minmax(0, 1fr))`,
|
||||||
|
gridTemplateRows:
|
||||||
|
`repeat(${ renderedSettings.rows }, minmax(0, 1fr))` }}
|
||||||
|
transition={{ duration: tileFlipDuration, ease: 'easeInOut' }}>
|
||||||
|
{Array.from ({ length: renderedTileCount }, (_, index) => {
|
||||||
|
const currentThumbnail =
|
||||||
|
displayedThumbnails[
|
||||||
|
index % Math.max (displayedThumbnails.length, 1)]
|
||||||
|
const frontThumbnail =
|
||||||
|
isFlippingTiles
|
||||||
|
? fromThumbnails[index % Math.max (fromThumbnails.length, 1)]
|
||||||
|
: currentThumbnail
|
||||||
|
const backThumbnail =
|
||||||
|
isFlippingTiles
|
||||||
|
? toThumbnails[index % Math.max (toThumbnails.length, 1)]
|
||||||
|
: currentThumbnail
|
||||||
|
const thumbnail =
|
||||||
|
displayedBackdropMode === 'winning_run'
|
||||||
|
|| displayedBackdropMode === 'guess'
|
||||||
|
? nextThumbnails[index % Math.max (nextThumbnails.length, 1)]
|
||||||
|
: currentThumbnail
|
||||||
|
if (!(thumbnail) || !(frontThumbnail) || !(backThumbnail))
|
||||||
|
return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={`${ duplicate }:${ index }`}
|
||||||
|
className="relative overflow-hidden"
|
||||||
|
layout={displayedBackdropMode !== 'normal'}
|
||||||
|
transition={{ duration: tileFlipDuration, ease: 'easeInOut' }}
|
||||||
|
style={{ perspective: 1600 }}>
|
||||||
|
{(displayedBackdropMode !== 'normal' || !(isFlippingTiles))
|
||||||
? (
|
? (
|
||||||
<>
|
<img
|
||||||
{renderTileSet ({
|
src={['intro', 'end'].includes (phase)
|
||||||
mode: displayedBackdropMode,
|
? mascotAsset
|
||||||
thumbnails: fromThumbnails,
|
: thumbnail}
|
||||||
settings: settingsForMode (displayedBackdropMode),
|
alt=""
|
||||||
tileCount: (settingsForMode (displayedBackdropMode).columns
|
className="absolute inset-0 h-full w-full object-cover"
|
||||||
* settingsForMode (displayedBackdropMode).rows),
|
style={{ opacity: renderedSettings.opacity }}/>)
|
||||||
scale: scaleForMode (displayedBackdropMode, displayedWinningRunCount),
|
|
||||||
opacity: 0 })}
|
|
||||||
{renderTileSet ({
|
|
||||||
mode: backdropMode,
|
|
||||||
thumbnails: toThumbnails,
|
|
||||||
settings: targetSettings,
|
|
||||||
tileCount: targetTileCount,
|
|
||||||
scale: scaleForMode (backdropMode, winningRunQuestionCount),
|
|
||||||
opacity: 1 })}
|
|
||||||
</>)
|
|
||||||
: (
|
: (
|
||||||
renderTileSet ({
|
<motion.div
|
||||||
mode: renderBackdropMode,
|
className="absolute inset-0"
|
||||||
thumbnails: renderThumbnails,
|
initial={{ rotateY: 0 }}
|
||||||
settings: renderedSettings,
|
animate={{ rotateY: 180 }}
|
||||||
tileCount: renderedTileCount,
|
transition={{
|
||||||
scale: renderedScale,
|
duration: tileFlipDuration,
|
||||||
withFlip: isFlippingTiles && !(isLeavingGuessBackdrop) }))}
|
ease: 'easeInOut' }}
|
||||||
|
style={{ transformStyle: 'preserve-3d' }}>
|
||||||
|
<img
|
||||||
|
src={backThumbnail}
|
||||||
|
alt=""
|
||||||
|
className="absolute inset-0 h-full w-full object-cover"
|
||||||
|
style={{
|
||||||
|
backfaceVisibility: 'hidden',
|
||||||
|
opacity: renderedSettings.opacity,
|
||||||
|
transform: 'rotateY(180deg)' }}/>
|
||||||
|
<img
|
||||||
|
src={frontThumbnail}
|
||||||
|
alt=""
|
||||||
|
className="absolute inset-0 h-full w-full object-cover"
|
||||||
|
style={{
|
||||||
|
backfaceVisibility: 'hidden',
|
||||||
|
opacity: renderedSettings.opacity }}/>
|
||||||
|
</motion.div>)}
|
||||||
|
</motion.div>)
|
||||||
|
})}
|
||||||
|
</motion.div>)
|
||||||
|
})}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
新しい課題から参照
ユーザをブロックする