Kaynağa Gözat

A first pass at smooth state transitions

Kirk Trombley 5 yıl önce
ebeveyn
işleme
6b71480861

+ 2 - 1
client/package.json

@@ -8,7 +8,8 @@
     "pretty-ms": "^5.1.0",
     "react": "^16.12.0",
     "react-dom": "^16.12.0",
-    "react-scripts": "^3.3.0-next.80"
+    "react-scripts": "^3.3.0-next.80",
+    "react-transition-group": "^4.3.0"
   },
   "scripts": {
     "start": "react-scripts start",

+ 49 - 22
client/src/App.js

@@ -1,4 +1,5 @@
-import React from 'react';
+import React, { useState } from 'react';
+import { CSSTransition } from 'react-transition-group';
 import styles from './App.module.css';
 import GamePanel from './components/screens/GamePanel';
 import HomePage from './components/screens/HomePage';
@@ -10,15 +11,6 @@ import { ERROR, IN_ROUND, POST_GAME, POST_ROUND, PRE_GAME, PRE_ROUND } from './d
 import { useGameState } from './domain/gameStore';
 import useDirectGameLinks from './hooks/useDirectGameLinks';
 
-const screenMap = {
-  [PRE_GAME]: HomePage,
-  [PRE_ROUND]: Lobby,
-  [IN_ROUND]: GamePanel,
-  [POST_ROUND]: RoundSummary,
-  [POST_GAME]: PlayerScores,
-  [ERROR]: () => <p>Application encountered unrecoverable error, please refresh the page.</p>
-};
-
 const needsHeaderFooter = {
   [PRE_GAME]: true,
   [PRE_ROUND]: true,
@@ -28,26 +20,61 @@ const needsHeaderFooter = {
   [ERROR]: true
 };
 
+const Header = () => (
+  <div className={styles.header}>
+    <p>TerrAssumptions!</p>
+  </div>
+)
+
+const Footer = () => (
+  <div className={styles.footer}>
+    <ApiInfo />
+  </div>
+)
+
+const State = ({ show, children, onEnter, onExited }) => (
+  <CSSTransition
+    in={show}
+    timeout={1000}
+    mountOnEnter
+    unmountOnExit
+    classNames="state"
+    onEnter={onEnter}
+    onExited={onExited}
+  >
+    <div className="state">
+      {children}
+    </div>
+  </CSSTransition>
+)
+
 export default () => {
+  const [st, setSt] = useState(true);
   const gameState = useGameState();
   useDirectGameLinks();
-  const Screen = screenMap[gameState];
   const needsHF = needsHeaderFooter[gameState];
 
   return (
     <React.StrictMode>
       <div className={styles.page}>
-        {needsHF && (
-          <div className={styles.header}>
-            <p>TerrAssumptions!</p>
-          </div>
-        )}
-        <Screen />
-        {needsHF && (
-          <div className={styles.footer}>
-            <ApiInfo />
-          </div>
-        )}
+        {needsHF && <Header />}
+        <State show={gameState === PRE_GAME} onExited={() => setSt(false)}>
+          <HomePage />
+        </State>
+        <State show={gameState === PRE_ROUND} onExited={() => setSt(false)}>
+          <Lobby />
+        </State>
+        {!st && gameState === IN_ROUND && <GamePanel />}
+        <State show={gameState === POST_ROUND} onEnter={() => setSt(true)} onExited={() => setSt(false)}>
+          <RoundSummary />
+        </State>
+        <State show={gameState === POST_GAME}>
+          <PlayerScores />
+        </State>
+        <State show={gameState === ERROR}>
+          <p>Application encountered unrecoverable error, please refresh the page.</p>
+        </State>
+        {needsHF && <Footer />}
       </div>
     </React.StrictMode>
   );

+ 1 - 0
client/src/components/screens/HomePage/HomePage.module.css

@@ -1,4 +1,5 @@
 .page {
+  width: 100%;
   height: 100%;
   display: flex;
   flex-flow: column-reverse nowrap;

+ 2 - 0
client/src/components/screens/Lobby/Lobby.module.css

@@ -1,4 +1,6 @@
 .page {
+  width: 100%;
+  height: 100%;
   flex: 1;
   display: flex;
   flex-flow: row nowrap;

+ 2 - 1
client/src/components/screens/PlayerScores/PlayerScores.module.css

@@ -3,7 +3,8 @@
   flex-flow: column nowrap;
   justify-content: space-between;
   align-items: center;
-  height: 100%;
+  padding: 10px;
+  height: calc(100% - 20px);
 }
 
 .top {

+ 27 - 0
client/src/index.css

@@ -50,3 +50,30 @@ button:disabled {
   width: 100% !important;
   height: 100% !important;
 }
+
+.state {
+  height: 100%;
+  width: 100%;
+}
+
+.state-enter {
+  opacity: 0;
+}
+
+.state-enter-active {
+  opacity: 1;
+  transition: opacity 1s;
+}
+
+.state-exit {
+  position: absolute;
+  z-index: 1;
+  opacity: 1;
+}
+
+.state-exit-active {
+  position: absolute;
+  z-index: 1;
+  opacity: 0;
+  transition: opacity 1s;
+}

+ 24 - 1
client/yarn.lock

@@ -966,7 +966,7 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
   version "7.9.2"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
   integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==
@@ -3292,6 +3292,11 @@ cssstyle@^1.0.0, cssstyle@^1.1.1:
   dependencies:
     cssom "0.3.x"
 
+csstype@^2.6.7:
+  version "2.6.10"
+  resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b"
+  integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==
+
 cyclist@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
@@ -3541,6 +3546,14 @@ dom-converter@^0.2:
   dependencies:
     utila "~0.4"
 
+dom-helpers@^5.0.1:
+  version "5.1.4"
+  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.1.4.tgz#4609680ab5c79a45f2531441f1949b79d6587f4b"
+  integrity sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==
+  dependencies:
+    "@babel/runtime" "^7.8.7"
+    csstype "^2.6.7"
+
 dom-serializer@0:
   version "0.2.2"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
@@ -8485,6 +8498,16 @@ react-scripts@^3.3.0-next.80:
   optionalDependencies:
     fsevents "2.1.2"
 
+react-transition-group@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.3.0.tgz#fea832e386cf8796c58b61874a3319704f5ce683"
+  integrity sha512-1qRV1ZuVSdxPlPf4O8t7inxUGpdyO5zG9IoNfJxSO0ImU2A1YWkEQvFPuIPZmMLkg5hYs7vv5mMOyfgSkvAwvw==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+    dom-helpers "^5.0.1"
+    loose-envify "^1.4.0"
+    prop-types "^15.6.2"
+
 react@^16.12.0:
   version "16.13.1"
   resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"