better wip hey
This commit is contained in:
parent
faff221ca6
commit
7e8e320c7d
@ -35,6 +35,7 @@
|
|||||||
*CLIENT*
|
*CLIENT*
|
||||||
reconnect based on time delta
|
reconnect based on time delta
|
||||||
menu footer
|
menu footer
|
||||||
|
fix refresh button
|
||||||
|
|
||||||
|
|
||||||
*SERVER*
|
*SERVER*
|
||||||
|
|||||||
@ -61,6 +61,7 @@ module.exports = {
|
|||||||
"react/jsx-uses-vars": 1,
|
"react/jsx-uses-vars": 1,
|
||||||
"react/prefer-stateless-function": 1,
|
"react/prefer-stateless-function": 1,
|
||||||
"react/prop-types": 0,
|
"react/prop-types": 0,
|
||||||
|
"react/no-unknown-property": 0,
|
||||||
|
|
||||||
// airbnb copypasta
|
// airbnb copypasta
|
||||||
// enforces getter/setter pairs in objects
|
// enforces getter/setter pairs in objects
|
||||||
|
|||||||
@ -79,8 +79,13 @@
|
|||||||
stroke-width: 2px;
|
stroke-width: 2px;
|
||||||
stroke: whitesmoke;
|
stroke: whitesmoke;
|
||||||
|
|
||||||
/* some stupid bug in chrome makes it fill the entire screen */
|
}
|
||||||
max-height: 10em;
|
|
||||||
|
/* some stupid bug in chrome makes it fill the entire screen */
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||||
|
#targeting {
|
||||||
|
max-height: 10em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.resolving #targeting {
|
.resolving #targeting {
|
||||||
|
|||||||
@ -418,4 +418,4 @@ button.equipping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile Nav*/
|
/* Mobile Nav*/
|
||||||
.instance .nav-btn { display: none; }
|
.instance-nav { display: none; }
|
||||||
|
|||||||
@ -2,12 +2,10 @@
|
|||||||
.instance {
|
.instance {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: min-content, min-content, min-content, 1fr;
|
grid-template-rows: min-content, 1fr;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"top"
|
|
||||||
"controls"
|
|
||||||
"vbox"
|
"vbox"
|
||||||
"constructs"
|
"constructs";
|
||||||
}
|
}
|
||||||
|
|
||||||
.instance .nav-btn { display: initial; }
|
.instance .nav-btn { display: initial; }
|
||||||
@ -131,4 +129,20 @@
|
|||||||
.instance-construct:last-child {
|
.instance-construct:last-child {
|
||||||
border-left: 1px solid #222;
|
border-left: 1px solid #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.instance-nav {
|
||||||
|
display: flex;
|
||||||
|
grid-area: nav;
|
||||||
|
margin-right: 0;
|
||||||
|
border-top: 2px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instance-nav button {
|
||||||
|
font-size: 150%;
|
||||||
|
border-right: 2px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instance-nav button:last-child {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -23,7 +23,7 @@ html, body, #mnml {
|
|||||||
/*padding: 0 20%;*/
|
/*padding: 0 20%;*/
|
||||||
|
|
||||||
/* stops inspector going skitz*/
|
/* stops inspector going skitz*/
|
||||||
/*overflow: hidden;*/
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@ -70,10 +70,11 @@ figure {
|
|||||||
padding: 0 2em;
|
padding: 0 2em;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 8fr;
|
grid-template-columns: 1fr 8fr;
|
||||||
grid-template-rows: min-content 1fr;
|
grid-template-rows: min-content 1fr min-content;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"hd hd"
|
"hd hd"
|
||||||
"nav main";
|
"nav main"
|
||||||
|
"nav footer";
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
@ -145,6 +146,7 @@ button, input {
|
|||||||
letter-spacing: 0.25em;
|
letter-spacing: 0.25em;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
/*the transitions */
|
/*the transitions */
|
||||||
transition-property: color;
|
transition-property: color;
|
||||||
@ -159,22 +161,6 @@ button:hover, button:focus {
|
|||||||
border-color: whitesmoke;
|
border-color: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.right[disabled]:hover, button.left[disabled]:hover {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.top:hover, button.top:focus {
|
|
||||||
box-shadow: inset 0 0.25em 0 0 whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.right:hover, button.right:focus {
|
|
||||||
box-shadow: inset -0.5em 0 0 0 whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.left:hover, button.left:focus {
|
|
||||||
box-shadow: inset 0.5em 0 0 0 whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
font-size: 150%;
|
font-size: 150%;
|
||||||
@ -313,18 +299,20 @@ header {
|
|||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-username {
|
.header-status {
|
||||||
letter-spacing: 0.05em;
|
margin: 1em 0;
|
||||||
display: inline;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-status {
|
.header-username {
|
||||||
text-align: right;
|
letter-spacing: 0.05em;
|
||||||
|
flex: 1;
|
||||||
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-status svg {
|
.header-status svg {
|
||||||
margin: 0.5em 0 0 1em;
|
margin: 0.5em 0 0 1em;
|
||||||
height: 1.5em;
|
height: 1em;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
stroke: whitesmoke;
|
stroke: whitesmoke;
|
||||||
}
|
}
|
||||||
@ -359,29 +347,14 @@ header {
|
|||||||
TEAM
|
TEAM
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.menu-constructs {
|
.team {
|
||||||
|
display: flex;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: min-content min-content;
|
grid-gap: 1em;
|
||||||
|
grid-template-columns: repeat(auto-fill,minmax(200px, 1fr));
|
||||||
grid-template-areas:
|
|
||||||
"top"
|
|
||||||
"team";
|
|
||||||
}
|
|
||||||
|
|
||||||
.constructs-list {
|
|
||||||
max-height: 100%;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
grid-area: team;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
grid-auto-rows: 1fr;
|
|
||||||
grid-gap: 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-construct {
|
.menu-construct {
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -544,10 +517,11 @@ main .top button {
|
|||||||
max-height: 0.25em;
|
max-height: 0.25em;
|
||||||
|
|
||||||
border: none;
|
border: none;
|
||||||
margin: 1em 0;
|
margin: 1em 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timer {
|
.timer {
|
||||||
|
flex: 1 0 100%;
|
||||||
background: whitesmoke;
|
background: whitesmoke;
|
||||||
transition-property: all;
|
transition-property: all;
|
||||||
transition-duration: 0.5s;
|
transition-duration: 0.5s;
|
||||||
@ -559,6 +533,33 @@ main .top button {
|
|||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
grid-area: footer;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer button {
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
background: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer button:disabled {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer button:not(:last-child) {
|
||||||
|
background: #222;
|
||||||
|
border-right: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer button .ready {
|
||||||
|
background: forestgreen;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-height: 900px), (max-width: 1500px) {
|
@media (max-height: 900px), (max-width: 1500px) {
|
||||||
#mnml {
|
#mnml {
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
@ -569,7 +570,6 @@ main .top button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile Nav*/
|
#nav-btn, #instance-nav {
|
||||||
#nav-btn {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,11 @@
|
|||||||
#mnml {
|
#mnml {
|
||||||
font-size: 8pt;
|
font-size: 8pt;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: min-content 1fr;
|
grid-template-rows: 1fr min-content;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"tnav hd "
|
"main"
|
||||||
"main main";
|
"footer";
|
||||||
}
|
}
|
||||||
|
|
||||||
#mnml button {
|
#mnml button {
|
||||||
@ -21,9 +21,8 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-btn {
|
#nav-btn, #instance-nav {
|
||||||
display: inline-block;
|
display: unset;
|
||||||
margin: 0 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#mnml.nav-visible nav {
|
#mnml.nav-visible nav {
|
||||||
@ -35,6 +34,10 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|||||||
36
client/src/components/footer.jsx
Normal file
36
client/src/components/footer.jsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// eslint-disable-next-line
|
||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
|
const TeamFooter = require('./team.footer');
|
||||||
|
const ListFooter = require('./list.footer');
|
||||||
|
const InstanceFooter = require('./instance.footer');
|
||||||
|
const GameFooter = require('./game.footer');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
({ nav, instance, game }) => {
|
||||||
|
return { nav, instance, game };
|
||||||
|
},
|
||||||
|
dispatch => ({
|
||||||
|
setShowNav: v => dispatch(actions.setShowNav(v)),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
function renderHeader(args) {
|
||||||
|
const {
|
||||||
|
nav,
|
||||||
|
instance,
|
||||||
|
game,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
if (instance) return <InstanceFooter />;
|
||||||
|
if (game) return <GameFooter />;
|
||||||
|
|
||||||
|
if (nav === 'team') return <TeamFooter />;
|
||||||
|
if (nav === 'list') return <ListFooter />;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = addState(renderHeader);
|
||||||
@ -1,122 +0,0 @@
|
|||||||
const preact = require('preact');
|
|
||||||
const GameConstruct = require('./game.construct');
|
|
||||||
const Targeting = require('./targeting.arrows');
|
|
||||||
|
|
||||||
function GamePanel(props) {
|
|
||||||
const {
|
|
||||||
game,
|
|
||||||
account,
|
|
||||||
resolution,
|
|
||||||
setActiveSkill,
|
|
||||||
setActiveConstruct,
|
|
||||||
sendInstanceState,
|
|
||||||
sendGameReady,
|
|
||||||
skip,
|
|
||||||
quit,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
if (!game) return <div>...</div>;
|
|
||||||
|
|
||||||
function actionClick() {
|
|
||||||
if (game.phase === 'Finish') {
|
|
||||||
sendInstanceState(game.instance);
|
|
||||||
quit();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolution) {
|
|
||||||
return skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
return sendGameReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
const otherTeams = game.players.filter(t => t.id !== account.id);
|
|
||||||
const playerTeam = game.players.find(t => t.id === account.id);
|
|
||||||
|
|
||||||
let actionText = 'Ready';
|
|
||||||
let actionStyles = 'instance-btn instance-ui-btn right';
|
|
||||||
if (game.phase === 'Finish') actionText = 'Done';
|
|
||||||
if (resolution) actionText = 'Skip';
|
|
||||||
if (actionText === 'Ready' && playerTeam.ready) actionStyles += ' ready';
|
|
||||||
|
|
||||||
const header = (
|
|
||||||
<div className="top">
|
|
||||||
<button
|
|
||||||
className={actionStyles}
|
|
||||||
onClick={() => actionClick()}>
|
|
||||||
{actionText}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
function findConstruct(id) {
|
|
||||||
const team = game.players.find(t => t.constructs.find(c => c.id === id));
|
|
||||||
if (team) return team.constructs.find(c => c.id === id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const zero = Date.parse(game.phase_start);
|
|
||||||
const now = Date.now();
|
|
||||||
const end = Date.parse(game.phase_end);
|
|
||||||
const timerPct = ((now - zero) / (end - zero) * 100);
|
|
||||||
const displayPct = resolution || game.phase === 'Finish'
|
|
||||||
? 0
|
|
||||||
: Math.min(timerPct, 100);
|
|
||||||
|
|
||||||
const displayColour = playerTeam.ready
|
|
||||||
? 'forestgreen'
|
|
||||||
: timerPct > 80
|
|
||||||
? 'red'
|
|
||||||
: 'whitesmoke';
|
|
||||||
|
|
||||||
const timerStyles = {
|
|
||||||
width: `${displayPct}%`,
|
|
||||||
background: displayColour,
|
|
||||||
};
|
|
||||||
|
|
||||||
const timer = (
|
|
||||||
<div className="timer-container">
|
|
||||||
<div className="timer" style={timerStyles} > </div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
function PlayerTeam(team) {
|
|
||||||
const constructs = team.constructs.map((c, i) =>
|
|
||||||
<GameConstruct key={c.id} i={i} construct={c} player={true} />);
|
|
||||||
return (
|
|
||||||
<div className="team player">
|
|
||||||
{constructs}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function OpponentTeam(team) {
|
|
||||||
const constructs = team.constructs.map((c, i) =>
|
|
||||||
<GameConstruct key={c.id} i={i} construct={c} player={false} />);
|
|
||||||
return (
|
|
||||||
<div className="team opponent">
|
|
||||||
{constructs}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const gameClasses = `game ${resolution ? 'resolving': ''}`;
|
|
||||||
|
|
||||||
function gameClick(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
setActiveConstruct(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<main className={gameClasses} onClick={gameClick} >
|
|
||||||
{header}
|
|
||||||
{timer}
|
|
||||||
{otherTeams.map(OpponentTeam)}
|
|
||||||
<Targeting />
|
|
||||||
{PlayerTeam(playerTeam, setActiveSkill)}
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = GamePanel;
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
const { connect } = require('preact-redux');
|
|
||||||
|
|
||||||
const actions = require('../actions');
|
|
||||||
|
|
||||||
const Game = require('./game.component');
|
|
||||||
|
|
||||||
const addState = connect(
|
|
||||||
function receiveState(state) {
|
|
||||||
const {
|
|
||||||
ws,
|
|
||||||
game,
|
|
||||||
account,
|
|
||||||
resolution,
|
|
||||||
showLog,
|
|
||||||
activeSkill,
|
|
||||||
activeConstruct,
|
|
||||||
} = state;
|
|
||||||
|
|
||||||
function selectSkillTarget(targetConstructId) {
|
|
||||||
if (activeSkill) {
|
|
||||||
return ws.sendGameSkill(game.id, activeSkill.constructId, targetConstructId, activeSkill.skill);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGameReady() {
|
|
||||||
ws.sendGameReady(game.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendInstanceState(instanceId) {
|
|
||||||
if (!instanceId) return false;
|
|
||||||
return ws.sendInstanceState(instanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// intercept self casting skills
|
|
||||||
if (activeSkill && activeSkill.skill.self_targeting) {
|
|
||||||
ws.sendGameSkill(game.id, activeSkill.constructId, null, activeSkill.skill.skill);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
game,
|
|
||||||
showLog,
|
|
||||||
account,
|
|
||||||
resolution,
|
|
||||||
activeSkill,
|
|
||||||
activeConstruct,
|
|
||||||
selectSkillTarget,
|
|
||||||
sendInstanceState,
|
|
||||||
sendGameReady,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
function receiveDispatch(dispatch) {
|
|
||||||
function setActiveSkill(constructId, skill) {
|
|
||||||
dispatch(actions.setActiveSkill(constructId, skill));
|
|
||||||
// particlesJS(`particles-${constructId}`, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setActiveConstruct(construct) {
|
|
||||||
dispatch(actions.setActiveConstruct(construct));
|
|
||||||
}
|
|
||||||
|
|
||||||
function quit() {
|
|
||||||
dispatch(actions.setGame(null));
|
|
||||||
dispatch(actions.setInstance(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleLog(v) {
|
|
||||||
dispatch(actions.setShowLog(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
function skip() {
|
|
||||||
dispatch(actions.setSkip(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
return { setActiveSkill, setActiveConstruct, quit, toggleLog, skip };
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = addState(Game);
|
|
||||||
136
client/src/components/game.footer.jsx
Normal file
136
client/src/components/game.footer.jsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const actions = require('../actions');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const {
|
||||||
|
ws,
|
||||||
|
game,
|
||||||
|
account,
|
||||||
|
resolution,
|
||||||
|
showNav,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
function sendGameReady() {
|
||||||
|
ws.sendGameReady(game.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendInstanceState(instanceId) {
|
||||||
|
if (!instanceId) return false;
|
||||||
|
return ws.sendInstanceState(instanceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
game,
|
||||||
|
account,
|
||||||
|
resolution,
|
||||||
|
sendInstanceState,
|
||||||
|
sendGameReady,
|
||||||
|
showNav,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function quit() {
|
||||||
|
dispatch(actions.setGame(null));
|
||||||
|
dispatch(actions.setInstance(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
function skip() {
|
||||||
|
dispatch(actions.setSkip(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setShowNav(v) {
|
||||||
|
return dispatch(actions.setShowNav(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { setShowNav, quit, skip };
|
||||||
|
}
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
function GameFooter(props) {
|
||||||
|
const {
|
||||||
|
game,
|
||||||
|
account,
|
||||||
|
resolution,
|
||||||
|
showNav,
|
||||||
|
|
||||||
|
quit,
|
||||||
|
skip,
|
||||||
|
setShowNav,
|
||||||
|
sendGameReady,
|
||||||
|
sendInstanceState,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
if (!game) {
|
||||||
|
return (
|
||||||
|
<footer id="footer">
|
||||||
|
<button id="nav-btn" onClick={() => setShowNav(!showNav)} >☰</button>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const playerTeam = game.players.find(t => t.id === account.id);
|
||||||
|
|
||||||
|
function actionClick() {
|
||||||
|
if (game.phase === 'Finish') {
|
||||||
|
sendInstanceState(game.instance);
|
||||||
|
quit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolution) {
|
||||||
|
return skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendGameReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
let actionText = 'Ready';
|
||||||
|
if (game.phase === 'Finish') actionText = 'Done';
|
||||||
|
if (resolution) actionText = 'Skip';
|
||||||
|
const ready = (actionText === 'Ready' && playerTeam.ready)
|
||||||
|
? 'ready'
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const zero = Date.parse(game.phase_start);
|
||||||
|
const now = Date.now();
|
||||||
|
const end = Date.parse(game.phase_end);
|
||||||
|
const timerPct = ((now - zero) / (end - zero) * 100);
|
||||||
|
const displayPct = resolution || game.phase === 'Finish'
|
||||||
|
? 0
|
||||||
|
: Math.min(timerPct, 100);
|
||||||
|
|
||||||
|
const displayColour = playerTeam.ready
|
||||||
|
? 'forestgreen'
|
||||||
|
: timerPct > 80
|
||||||
|
? 'red'
|
||||||
|
: 'whitesmoke';
|
||||||
|
|
||||||
|
const timerStyles = {
|
||||||
|
width: `${displayPct}%`,
|
||||||
|
background: displayColour,
|
||||||
|
};
|
||||||
|
|
||||||
|
const timer = (
|
||||||
|
<div className="timer-container">
|
||||||
|
<div className="timer" style={timerStyles} > </div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer>
|
||||||
|
{timer}
|
||||||
|
<button
|
||||||
|
className={ready}
|
||||||
|
onClick={() => actionClick()}>
|
||||||
|
{actionText}
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(GameFooter);
|
||||||
107
client/src/components/game.jsx
Normal file
107
client/src/components/game.jsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const actions = require('../actions');
|
||||||
|
|
||||||
|
const GameConstruct = require('./game.construct');
|
||||||
|
const Targeting = require('./targeting.arrows');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const {
|
||||||
|
ws,
|
||||||
|
game,
|
||||||
|
account,
|
||||||
|
resolution,
|
||||||
|
activeSkill,
|
||||||
|
activeConstruct,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
function selectSkillTarget(targetConstructId) {
|
||||||
|
if (activeSkill) {
|
||||||
|
return ws.sendGameSkill(game.id, activeSkill.constructId, targetConstructId, activeSkill.skill);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// intercept self casting skills
|
||||||
|
if (activeSkill && activeSkill.skill.self_targeting) {
|
||||||
|
ws.sendGameSkill(game.id, activeSkill.constructId, null, activeSkill.skill.skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
game,
|
||||||
|
account,
|
||||||
|
resolution,
|
||||||
|
activeSkill,
|
||||||
|
activeConstruct,
|
||||||
|
selectSkillTarget,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function setActiveSkill(constructId, skill) {
|
||||||
|
dispatch(actions.setActiveSkill(constructId, skill));
|
||||||
|
// particlesJS(`particles-${constructId}`, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveConstruct(construct) {
|
||||||
|
dispatch(actions.setActiveConstruct(construct));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { setActiveSkill, setActiveConstruct };
|
||||||
|
}
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
function Game(props) {
|
||||||
|
const {
|
||||||
|
game,
|
||||||
|
account,
|
||||||
|
resolution,
|
||||||
|
setActiveSkill,
|
||||||
|
setActiveConstruct,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
if (!game) return <div>...</div>;
|
||||||
|
|
||||||
|
const otherTeams = game.players.filter(t => t.id !== account.id);
|
||||||
|
const playerTeam = game.players.find(t => t.id === account.id);
|
||||||
|
|
||||||
|
function PlayerTeam(team) {
|
||||||
|
const constructs = team.constructs.map((c, i) =>
|
||||||
|
<GameConstruct key={c.id} i={i} construct={c} player={true} />);
|
||||||
|
return (
|
||||||
|
<div className="team player">
|
||||||
|
{constructs}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function OpponentTeam(team) {
|
||||||
|
const constructs = team.constructs.map((c, i) =>
|
||||||
|
<GameConstruct key={c.id} i={i} construct={c} player={false} />);
|
||||||
|
return (
|
||||||
|
<div className="team opponent">
|
||||||
|
{constructs}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gameClasses = `game ${resolution ? 'resolving': ''}`;
|
||||||
|
|
||||||
|
function gameClick(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
setActiveConstruct(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className={gameClasses} onClick={gameClick} >
|
||||||
|
{otherTeams.map(OpponentTeam)}
|
||||||
|
<Targeting />
|
||||||
|
{PlayerTeam(playerTeam, setActiveSkill)}
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Game);
|
||||||
@ -1,15 +0,0 @@
|
|||||||
const { connect } = require('preact-redux');
|
|
||||||
|
|
||||||
const Header = require('./header.component');
|
|
||||||
const actions = require('./../actions');
|
|
||||||
|
|
||||||
const addState = connect(
|
|
||||||
({ account, ping, showNav }) => {
|
|
||||||
return { account, ping, showNav };
|
|
||||||
},
|
|
||||||
dispatch => ({
|
|
||||||
setShowNav: v => dispatch(actions.setShowNav(v)),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = addState(Header);
|
|
||||||
@ -1,7 +1,9 @@
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
const { saw } = require('./shapes');
|
const { saw } = require('./shapes');
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
function pingColour(ping) {
|
function pingColour(ping) {
|
||||||
if (ping < 100) return 'forestgreen';
|
if (ping < 100) return 'forestgreen';
|
||||||
@ -9,8 +11,14 @@ function pingColour(ping) {
|
|||||||
return 'red';
|
return 'red';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
({ account, ping, showNav }) => {
|
||||||
|
return { account, ping };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
function renderHeader(args) {
|
function renderHeader(args) {
|
||||||
const { account, ping, setShowNav, showNav } = args;
|
const { account, ping } = args;
|
||||||
|
|
||||||
const accountStatus = account
|
const accountStatus = account
|
||||||
? (<div className="header-status">
|
? (<div className="header-status">
|
||||||
@ -22,14 +30,11 @@ function renderHeader(args) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<h1 className="header-title">
|
<h1 className="header-title">mnml.gg</h1>
|
||||||
<span id="nav-btn" onClick={() => setShowNav(!showNav)} >☰</span>
|
|
||||||
mnml.gg
|
|
||||||
</h1>
|
|
||||||
{accountStatus}
|
{accountStatus}
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = renderHeader;
|
module.exports = addState(renderHeader);
|
||||||
@ -10,13 +10,8 @@ const actions = require('../actions');
|
|||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const { ws, instance, player, account, nav } = state;
|
const { ws, instance, nav } = state;
|
||||||
|
return { instance, nav };
|
||||||
function sendInstanceReady() {
|
|
||||||
return ws.sendInstanceReady(instance.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { player, instance, sendInstanceReady, nav };
|
|
||||||
},
|
},
|
||||||
|
|
||||||
function receiveDispatch(dispatch) {
|
function receiveDispatch(dispatch) {
|
||||||
@ -24,13 +19,8 @@ const addState = connect(
|
|||||||
return dispatch(actions.setInfo(c));
|
return dispatch(actions.setInfo(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNav(v) {
|
|
||||||
return dispatch(actions.setNav(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setInfo,
|
setInfo,
|
||||||
setNav,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -38,62 +28,13 @@ const addState = connect(
|
|||||||
function Instance(args) {
|
function Instance(args) {
|
||||||
const {
|
const {
|
||||||
instance,
|
instance,
|
||||||
player,
|
|
||||||
sendInstanceReady,
|
|
||||||
setInfo,
|
setInfo,
|
||||||
|
|
||||||
nav,
|
nav,
|
||||||
setNav,
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (!instance) return false;
|
if (!instance) return false;
|
||||||
|
|
||||||
function hoverInfo(e, info) {
|
|
||||||
e.stopPropagation();
|
|
||||||
return setInfo(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rdyClasses = `instance-btn instance-ui-btn ${player.ready ? 'ready' : ''}`;
|
|
||||||
const readyInfo = instance.phase === 'Lobby'
|
|
||||||
? 'lobbyReady'
|
|
||||||
: 'ready';
|
|
||||||
const readyBtn = (
|
|
||||||
<button
|
|
||||||
className={rdyClasses}
|
|
||||||
onMouseOver={e => hoverInfo(e, readyInfo)}
|
|
||||||
onClick={() => sendInstanceReady()}>
|
|
||||||
Ready
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
|
|
||||||
function navClick() {
|
|
||||||
if (nav === 'vbox') return setNav('constructs');
|
|
||||||
return setNav('vbox');
|
|
||||||
}
|
|
||||||
|
|
||||||
const navBtn = (
|
|
||||||
<button
|
|
||||||
className="nav-btn"
|
|
||||||
onClick={navClick}>
|
|
||||||
{nav === 'vbox' ? 'Constructs' : 'Vbox'}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const actionBtn = player
|
|
||||||
? readyBtn
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// TIMER
|
|
||||||
const zero = Date.parse(instance.phase_start);
|
|
||||||
const now = Date.now();
|
|
||||||
const end = Date.parse(instance.phase_end);
|
|
||||||
const timerPct = ((now - zero) / (end - zero) * 100);
|
|
||||||
const timerStyles = {
|
|
||||||
width: `${timerPct < 100 ? timerPct : 0}%`,
|
|
||||||
background: player.ready ? 'forestgreen' : 'whitesmoke',
|
|
||||||
};
|
|
||||||
|
|
||||||
function playerRound(id) {
|
function playerRound(id) {
|
||||||
if (!instance.rounds.length) return null;
|
if (!instance.rounds.length) return null;
|
||||||
return instance.rounds[instance.rounds.length - 1].find(r => r.player_ids.includes(id));
|
return instance.rounds[instance.rounds.length - 1].find(r => r.player_ids.includes(id));
|
||||||
@ -139,21 +80,10 @@ function Instance(args) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const timer = (
|
|
||||||
<div className="timer-container">
|
|
||||||
<div className="timer" style={timerStyles} > </div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const instanceClasses = `instance ${nav === 'constructs' ? 'constructs-visible' : ''}`;
|
const instanceClasses = `instance ${nav === 'constructs' ? 'constructs-visible' : ''}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className={instanceClasses} onMouseOver={() => setInfo(null)} >
|
<main className={instanceClasses} onMouseOver={() => setInfo(null)} >
|
||||||
<div className="top">
|
|
||||||
{actionBtn}
|
|
||||||
{timer}
|
|
||||||
{navBtn}
|
|
||||||
</div>
|
|
||||||
<ScoreBoard />
|
<ScoreBoard />
|
||||||
<Vbox />
|
<Vbox />
|
||||||
<InfoContainer />
|
<InfoContainer />
|
||||||
|
|||||||
126
client/src/components/instance.footer.jsx
Normal file
126
client/src/components/instance.footer.jsx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const actions = require('../actions');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const { ws, instance, player, nav, showNav } = state;
|
||||||
|
|
||||||
|
function sendInstanceReady() {
|
||||||
|
return ws.sendInstanceReady(instance.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { player, instance, sendInstanceReady, nav, showNav };
|
||||||
|
},
|
||||||
|
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function setShowNav(v) {
|
||||||
|
return dispatch(actions.setShowNav(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setInfo(c) {
|
||||||
|
return dispatch(actions.setInfo(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNav(v) {
|
||||||
|
return dispatch(actions.setNav(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setInfo,
|
||||||
|
setNav,
|
||||||
|
setShowNav,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function Instance(args) {
|
||||||
|
const {
|
||||||
|
instance,
|
||||||
|
player,
|
||||||
|
nav,
|
||||||
|
showNav,
|
||||||
|
|
||||||
|
setInfo,
|
||||||
|
setNav,
|
||||||
|
setShowNav,
|
||||||
|
|
||||||
|
sendInstanceReady,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
if (!instance || !player) {
|
||||||
|
return (
|
||||||
|
<footer id="footer">
|
||||||
|
<button id="nav-btn" onClick={() => setShowNav(!showNav)} >☰</button>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hoverInfo(e, info) {
|
||||||
|
e.stopPropagation();
|
||||||
|
return setInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rdyClasses = `${player.ready ? 'ready' : ''}`;
|
||||||
|
const readyInfo = instance.phase === 'Lobby'
|
||||||
|
? 'lobbyReady'
|
||||||
|
: 'ready';
|
||||||
|
|
||||||
|
const readyBtn = (
|
||||||
|
<button
|
||||||
|
className={rdyClasses}
|
||||||
|
onMouseOver={e => hoverInfo(e, readyInfo)}
|
||||||
|
onClick={() => sendInstanceReady()}>
|
||||||
|
Ready
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
function navClick() {
|
||||||
|
if (nav === 'vbox') return setNav('constructs');
|
||||||
|
return setNav('vbox');
|
||||||
|
}
|
||||||
|
|
||||||
|
const navBtn = instance.phase === 'InProgress'
|
||||||
|
? (
|
||||||
|
<button
|
||||||
|
id="instance-nav"
|
||||||
|
onClick={navClick}>
|
||||||
|
{nav === 'vbox' ? 'Constructs' : 'Vbox'}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const zero = Date.parse(instance.phase_start);
|
||||||
|
const now = Date.now();
|
||||||
|
const end = Date.parse(instance.phase_end);
|
||||||
|
const timerPct = ((now - zero) / (end - zero) * 100);
|
||||||
|
|
||||||
|
const displayColour = player.ready
|
||||||
|
? 'forestgreen'
|
||||||
|
: timerPct > 80
|
||||||
|
? 'red'
|
||||||
|
: 'whitesmoke';
|
||||||
|
|
||||||
|
const timerStyles = {
|
||||||
|
width: `${timerPct}%`,
|
||||||
|
background: displayColour,
|
||||||
|
};
|
||||||
|
|
||||||
|
const timer = (
|
||||||
|
<div className="timer-container">
|
||||||
|
<div className="timer" style={timerStyles} > </div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer id="footer">
|
||||||
|
{timer}
|
||||||
|
<button id="nav-btn" onClick={() => setShowNav(!showNav)} >☰</button>
|
||||||
|
{navBtn}
|
||||||
|
{readyBtn}
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Instance);
|
||||||
47
client/src/components/list.footer.jsx
Normal file
47
client/src/components/list.footer.jsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
const { connect } = require('preact-redux');
|
||||||
|
const preact = require('preact');
|
||||||
|
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const { showNav } = state;
|
||||||
|
return { showNav };
|
||||||
|
},
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function navToTeam() {
|
||||||
|
return dispatch(actions.setNav('team'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setShowNav(v) {
|
||||||
|
return dispatch(actions.setShowNav(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
navToTeam,
|
||||||
|
setShowNav,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function ListFooter(args) {
|
||||||
|
const {
|
||||||
|
showNav,
|
||||||
|
|
||||||
|
navToTeam,
|
||||||
|
setShowNav,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer>
|
||||||
|
<button id="nav-btn" onClick={() => setShowNav(!showNav)} >☰</button>
|
||||||
|
<button
|
||||||
|
className="instance-btn instance-ui-btn left"
|
||||||
|
onClick={() => navToTeam()}>
|
||||||
|
Change Constructs
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(ListFooter);
|
||||||
@ -37,15 +37,6 @@ const addState = connect(
|
|||||||
instanceList,
|
instanceList,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
function receiveDispatch(dispatch) {
|
|
||||||
function navToTeam() {
|
|
||||||
return dispatch(actions.setNav('team'));
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
navToTeam,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function List(args) {
|
function List(args) {
|
||||||
@ -57,7 +48,6 @@ function List(args) {
|
|||||||
sendInstanceJoin,
|
sendInstanceJoin,
|
||||||
sendInstanceList,
|
sendInstanceList,
|
||||||
instanceList,
|
instanceList,
|
||||||
navToTeam,
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
function listElements() {
|
function listElements() {
|
||||||
@ -120,20 +110,8 @@ function List(args) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const header = (
|
|
||||||
<div className="top">
|
|
||||||
<button
|
|
||||||
className="instance-btn instance-ui-btn left"
|
|
||||||
onClick={() => navToTeam()}>
|
|
||||||
Select Constructs
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="menu-instances">
|
<main className="menu-instances">
|
||||||
{header}
|
|
||||||
<div className="construct-list">
|
<div className="construct-list">
|
||||||
{constructPanels}
|
{constructPanels}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,7 +3,7 @@ const preact = require('preact');
|
|||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
const Login = require('./login');
|
const Login = require('./login');
|
||||||
const GameContainer = require('./game.container');
|
const Game = require('./game');
|
||||||
const Instance = require('./instance.component');
|
const Instance = require('./instance.component');
|
||||||
const Team = require('./team');
|
const Team = require('./team');
|
||||||
const List = require('./list');
|
const List = require('./list');
|
||||||
@ -28,7 +28,7 @@ function Main(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (game) {
|
if (game) {
|
||||||
return <GameContainer />;
|
return <Game />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
const Header = require('./header.container');
|
// const Header = require('./header');
|
||||||
const Main = require('./main');
|
const Main = require('./main');
|
||||||
const Nav = require('./nav');
|
const Nav = require('./nav');
|
||||||
|
const Footer = require('./footer');
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
state => ({ showNav: state.showNav })
|
state => ({ showNav: state.showNav })
|
||||||
);
|
);
|
||||||
|
|
||||||
const Mnml = ({ showNav, setShowNav }) =>
|
const Mnml = ({ showNav }) =>
|
||||||
<div id="mnml" className={showNav ? 'nav-visible' : ''}>
|
<div id="mnml" className={showNav ? 'nav-visible' : ''}>
|
||||||
<Header />
|
|
||||||
<Nav />
|
<Nav />
|
||||||
<Main />
|
<Main />
|
||||||
|
<Footer />
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
module.exports = addState(Mnml);
|
module.exports = addState(Mnml);
|
||||||
|
|||||||
@ -3,9 +3,17 @@ const preact = require('preact');
|
|||||||
const { Fragment } = require('preact');
|
const { Fragment } = require('preact');
|
||||||
const actions = require('../actions');
|
const actions = require('../actions');
|
||||||
|
|
||||||
|
const { saw } = require('./shapes');
|
||||||
|
|
||||||
const testGame = process.env.NODE_ENV === 'development' && require('./../test.game');
|
const testGame = process.env.NODE_ENV === 'development' && require('./../test.game');
|
||||||
const testInstance = process.env.NODE_ENV === 'development' && require('./../test.instance');
|
const testInstance = process.env.NODE_ENV === 'development' && require('./../test.instance');
|
||||||
|
|
||||||
|
function pingColour(ping) {
|
||||||
|
if (ping < 100) return 'forestgreen';
|
||||||
|
if (ping < 200) return 'yellow';
|
||||||
|
return 'red';
|
||||||
|
}
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
@ -13,7 +21,8 @@ const addState = connect(
|
|||||||
account,
|
account,
|
||||||
instances,
|
instances,
|
||||||
team,
|
team,
|
||||||
// constructs,
|
ping,
|
||||||
|
|
||||||
game,
|
game,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
@ -34,6 +43,7 @@ const addState = connect(
|
|||||||
instances,
|
instances,
|
||||||
team,
|
team,
|
||||||
game,
|
game,
|
||||||
|
ping,
|
||||||
sendInstanceState,
|
sendInstanceState,
|
||||||
sendAccountInstances,
|
sendAccountInstances,
|
||||||
sendInstanceList,
|
sendInstanceList,
|
||||||
@ -79,14 +89,15 @@ const addState = connect(
|
|||||||
function Nav(args) {
|
function Nav(args) {
|
||||||
const {
|
const {
|
||||||
account,
|
account,
|
||||||
sendInstanceState,
|
ping,
|
||||||
sendAccountInstances,
|
|
||||||
sendInstanceList,
|
|
||||||
|
|
||||||
team,
|
team,
|
||||||
instances,
|
instances,
|
||||||
game,
|
game,
|
||||||
|
|
||||||
|
sendInstanceState,
|
||||||
|
sendAccountInstances,
|
||||||
|
sendInstanceList,
|
||||||
|
|
||||||
setTestGame,
|
setTestGame,
|
||||||
setTestInstance,
|
setTestInstance,
|
||||||
setNav,
|
setNav,
|
||||||
@ -122,8 +133,18 @@ function Nav(args) {
|
|||||||
|
|
||||||
const canJoin = team.some(c => !c);
|
const canJoin = team.some(c => !c);
|
||||||
|
|
||||||
|
const accountStatus = account
|
||||||
|
? (<div className="header-status">
|
||||||
|
<h2 className="header-username">{account.name}</h2>
|
||||||
|
{saw(pingColour(ping))}
|
||||||
|
<div className="ping-text">{ping}ms</div>
|
||||||
|
</div>)
|
||||||
|
: false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav onClick={hideNav} >
|
<nav onClick={hideNav} >
|
||||||
|
<h1 className="header-title">mnml.gg</h1>
|
||||||
|
{accountStatus}
|
||||||
<button onClick={() => navTo('team')}>1. Select Team</button>
|
<button onClick={() => navTo('team')}>1. Select Team</button>
|
||||||
<button disabled={canJoin} onClick={() => navTo('list')}>2. Join</button>
|
<button disabled={canJoin} onClick={() => navTo('list')}>2. Join</button>
|
||||||
<hr />
|
<hr />
|
||||||
|
|||||||
56
client/src/components/team.footer.jsx
Normal file
56
client/src/components/team.footer.jsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const { team, showNav } = state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
team,
|
||||||
|
showNav,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function navToList() {
|
||||||
|
dispatch(actions.setGame(null));
|
||||||
|
dispatch(actions.setInstance(null));
|
||||||
|
return dispatch(actions.setNav('list'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setShowNav(v) {
|
||||||
|
return dispatch(actions.setShowNav(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
navToList,
|
||||||
|
setShowNav,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function TeamFooter(args) {
|
||||||
|
const {
|
||||||
|
showNav,
|
||||||
|
team,
|
||||||
|
navToList,
|
||||||
|
setShowNav,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
if (!team) return false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer>
|
||||||
|
<button id="nav-btn" onClick={() => setShowNav(!showNav)} >☰</button>
|
||||||
|
<button
|
||||||
|
disabled={team.some(c => !c)}
|
||||||
|
className="instance-btn instance-ui-btn right"
|
||||||
|
onClick={() => navToList()}>
|
||||||
|
Join Instance
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(TeamFooter);
|
||||||
@ -12,14 +12,13 @@ const idSort = stringSort('id');
|
|||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const { ws, constructs, team, account } = state;
|
const { ws, constructs, team } = state;
|
||||||
|
|
||||||
function sendConstructSpawn(name) {
|
function sendConstructSpawn(name) {
|
||||||
return ws.sendConstructSpawn(name);
|
return ws.sendConstructSpawn(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
account,
|
|
||||||
constructs,
|
constructs,
|
||||||
team,
|
team,
|
||||||
sendConstructSpawn,
|
sendConstructSpawn,
|
||||||
@ -31,29 +30,19 @@ const addState = connect(
|
|||||||
dispatch(actions.setTeam(constructIds));
|
dispatch(actions.setTeam(constructIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
function navToList() {
|
|
||||||
dispatch(actions.setGame(null));
|
|
||||||
dispatch(actions.setInstance(null));
|
|
||||||
return dispatch(actions.setNav('list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setTeam,
|
setTeam,
|
||||||
navToList,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function Team(args) {
|
function Team(args) {
|
||||||
const {
|
const {
|
||||||
account,
|
|
||||||
constructs,
|
constructs,
|
||||||
team,
|
team,
|
||||||
|
|
||||||
setTeam,
|
setTeam,
|
||||||
sendConstructSpawn,
|
sendConstructSpawn,
|
||||||
navToList,
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (!constructs) return <div></div>;
|
if (!constructs) return <div></div>;
|
||||||
@ -98,25 +87,10 @@ function Team(args) {
|
|||||||
const spawnButtons = range(spawnButtonsNum)
|
const spawnButtons = range(spawnButtonsNum)
|
||||||
.map(i => <SpawnButton key={constructs.length + i} spawn={name => sendConstructSpawn(name)} />);
|
.map(i => <SpawnButton key={constructs.length + i} spawn={name => sendConstructSpawn(name)} />);
|
||||||
|
|
||||||
|
|
||||||
const header = (
|
|
||||||
<div className="top">
|
|
||||||
<button
|
|
||||||
disabled={team.some(c => !c)}
|
|
||||||
className="instance-btn instance-ui-btn right"
|
|
||||||
onClick={() => navToList()}>
|
|
||||||
Join Instance
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="menu-constructs">
|
<main className="team">
|
||||||
{header}
|
{constructPanels}
|
||||||
<div className="constructs-list">
|
{spawnButtons}
|
||||||
{constructPanels}
|
|
||||||
{spawnButtons}
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ function errorToast(err) {
|
|||||||
return toast.error({
|
return toast.error({
|
||||||
title: 'BEEP BOOP',
|
title: 'BEEP BOOP',
|
||||||
message: err,
|
message: err,
|
||||||
position: 'bottomCenter',
|
position: 'topRight',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ function createSocket(events) {
|
|||||||
ws.addEventListener('open', () => {
|
ws.addEventListener('open', () => {
|
||||||
toast.info({
|
toast.info({
|
||||||
message: 'connected',
|
message: 'connected',
|
||||||
position: 'bottomCenter',
|
position: 'topRight',
|
||||||
});
|
});
|
||||||
|
|
||||||
sendPing();
|
sendPing();
|
||||||
@ -303,7 +303,7 @@ function createSocket(events) {
|
|||||||
console.error('WebSocket closed', event);
|
console.error('WebSocket closed', event);
|
||||||
toast.warning({
|
toast.warning({
|
||||||
message: 'disconnected',
|
message: 'disconnected',
|
||||||
position: 'bottomCenter',
|
position: 'topRight',
|
||||||
});
|
});
|
||||||
return setTimeout(connect, 5000);
|
return setTimeout(connect, 5000);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user