better wip hey

This commit is contained in:
ntr 2019-06-03 23:24:48 +10:00
parent faff221ca6
commit 7e8e320c7d
24 changed files with 645 additions and 422 deletions

View File

@ -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*

View File

@ -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

View File

@ -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 {

View File

@ -418,4 +418,4 @@ button.equipping {
} }
/* Mobile Nav*/ /* Mobile Nav*/
.instance .nav-btn { display: none; } .instance-nav { display: none; }

View File

@ -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;
}
} }

View File

@ -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;
} }

View File

@ -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;
} }

View 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);

View File

@ -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} >&nbsp;</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;

View File

@ -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);

View 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} >&nbsp;</div>
</div>
);
return (
<footer>
{timer}
<button
className={ready}
onClick={() => actionClick()}>
{actionText}
</button>
</footer>
);
}
module.exports = addState(GameFooter);

View 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);

View File

@ -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);

View File

@ -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);

View File

@ -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} >&nbsp;</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 />

View 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} >&nbsp;</div>
</div>
);
return (
<footer id="footer">
{timer}
<button id="nav-btn" onClick={() => setShowNav(!showNav)} ></button>
{navBtn}
{readyBtn}
</footer>
);
}
module.exports = addState(Instance);

View 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);

View File

@ -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>

View File

@ -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) {

View File

@ -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);

View File

@ -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 />

View 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);

View File

@ -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>
); );
} }

View File

@ -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);
}); });