welcome to mnml

This commit is contained in:
ntr 2019-08-26 18:43:05 +10:00
parent 6ff292ff3c
commit 65514f576a
12 changed files with 447 additions and 182 deletions

View File

@ -74,6 +74,10 @@ figure {
text-align: center;
}
p {
margin-bottom: 1em;
}
#mnml {
display: grid;
grid-template-columns: minmax(min-content, 1fr) 8fr 1fr;
@ -189,11 +193,28 @@ button[disabled] {
LOGIN
*/
.login {
width: 50%;
display: flex;
flex-flow: column;
margin-bottom: 2em;
.welcome {
.highlight {
color: black;
background: @white;
border: 1px solid @white;
}
.login {
width: 50%;
display: flex;
flex-flow: column;
margin-bottom: 2em;
}
.options {
width: 50%;
display: flex;
flex-flow: row;
button {
flex: 1;
}
}
h2 {
margin-bottom: 0.5em;

View File

@ -53,10 +53,19 @@
padding: 0 0.5em;
}
.login {
.welcome .login {
width: 100%;
}
.welcome .options {
width: 100%;
flex-flow: row wrap;
}
.welcome .options button {
flex: 1 0 50%;
}
.timer-container {
margin: 0.5em 0 0 0;
}

View File

@ -16,7 +16,10 @@
</head>
</head>
<body>
<noscript>js is required to run mnml</noscript>
<noscript>
<p>js is required to run mnml.</p>
<p>this site has no trackers or ads.</p>
</noscript>
</body>
<script src="https://js.stripe.com/v3/"></script>
<script src="./index.js"></script>

View File

@ -1,170 +0,0 @@
// eslint-disable-next-line
const preact = require('preact');
const { Component } = require('preact')
const { connect } = require('preact-redux');
const linkState = require('linkstate').default;
const { postData, errorToast } = require('../utils');
const addState = connect(
(state) => {
const {
ws
} = state;
function submitLogin(name, password) {
postData('/account/login', { name, password })
.then(res => res.json())
.then(data => {
if (data.error) return errorToast(data.error);
console.log(data.response);
ws.connect();
})
.catch(error => errorToast(error));
}
function submitRegister(name, password, code) {
postData('/account/register', { name, password, code })
.then(res => res.json())
.then(data => {
if (data.error) return errorToast(data.error);
console.log(data.response);
ws.connect();
})
.catch(error => errorToast(error));
}
return {
submitLogin,
submitRegister,
}
},
);
class Login extends Component {
constructor(props) {
super(props);
this.state = {
login: { name: '', password: '', code: ''},
register: { name: '', password: '', confirm: '', code: ''},
};
this.loginSubmit = this.loginSubmit.bind(this);
this.registerSubmit = this.registerSubmit.bind(this);
}
loginSubmit(event) {
event.preventDefault();
console.log(this.state);
this.props.submitLogin(this.state.login.name, this.state.login.password);
this.setState({ login: { name: '', password: '' }});
}
registerSubmit(event) {
event.preventDefault();
this.props.submitRegister(this.state.register.name, this.state.register.password, this.state.register.code);
this.setState({ register: { name: '', password: '', confirm: '', code: ''}});
}
render() {
const registerConfirm = () =>
this.state.register.password === this.state.register.confirm;
const loginDisabled = () => {
const { password, name } = this.state.login;
return !(password && name);
}
const registerDisabled = () => {
const { password, name, code } = this.state.register;
return !(registerConfirm() && password && name && code);
}
return (
<main>
<h1>mnml.gg</h1>
<div class="login">
<div>mnml is an abstract turn based strategy game</div>
<div>free to play</div>
<div>no email required</div>
</div>
<div class="login">
<h2>Login</h2>
<label for="username">Username</label>
<input
class="login-input"
type="email"
placeholder="username"
tabIndex={1}
value={this.state.login.name}
onInput={linkState(this, 'login.name')}
/>
<label for="password">Password</label>
<input
class="login-input"
type="password"
placeholder="password"
tabIndex={2}
value={this.state.login.password}
onInput={linkState(this, 'login.password')}
/>
<button
class="login-btn"
tabIndex={4}
disabled={loginDisabled()}
onClick={this.loginSubmit}>
Login
</button>
</div>
<div class="login">
<h2>Register</h2>
<label for="username">Username</label>
<input
class="login-input"
type="email"
placeholder="username"
value={this.state.register.name}
onInput={linkState(this, 'register.name')}
/>
<label for="password">Password - min 12 chars</label>
<input
class="login-input"
type="password"
placeholder="password"
value={this.state.register.password}
onInput={linkState(this, 'register.password')}
/>
<label for="confirm">Confirm Password</label>
<input
class={`${registerConfirm() ? '' : 'red'} login-input`}
type="password"
placeholder="confirm"
value={this.state.register.confirm}
onInput={linkState(this, 'register.confirm')}
/>
<label for="code">Access Code</label>
<input
class="login-input"
type="text"
placeholder="code"
value={this.state.register.code}
onInput={linkState(this, 'register.code')}
/>
<button
class="login-btn"
disabled={registerDisabled()}
onClick={this.registerSubmit}>
Register
</button>
<button
class="login-btn"
onClick={() => document.location.assign('https://discord.gg/YJJgurM')}>
Discord + Codes
</button>
</div>
</main>
);
}
}
module.exports = addState(Login);

View File

@ -2,7 +2,7 @@
const preact = require('preact');
const { connect } = require('preact-redux');
const Login = require('./login');
const Welcome = require('./welcome');
const Game = require('./game');
const Instance = require('./instance.component');
const Team = require('./team');
@ -25,7 +25,7 @@ function Main(props) {
} = props;
if (!account) {
return <Login />;
return <Welcome />;
}
if (game) {

View File

@ -0,0 +1,69 @@
// eslint-disable-next-line
const preact = require('preact');
const { Component } = require('preact')
const { connect } = require('preact-redux');
const linkState = require('linkstate').default;
const { postData, errorToast, infoToast } = require('../utils');
const addState = connect(
(state) => {
const {
ws
} = state;
function submitRegister(name, password, code) {
postData('/account/register', { name, password, code })
.then(res => res.json())
.then(data => {
if (data.error) return errorToast(data.error);
infoToast(data.message);
ws.connect();
})
.catch(error => errorToast(error));
}
return {
submitRegister,
}
},
);
function Register(args) {
const {
submitRegister,
navRegister,
} = args;
return (
<div class="login">
<p>
mnml is made deep in the southern hemisphere by ntr & mashy.
</p>
<p>
if you like this game please support the development by buying credits or subscribing.
</p>
<p>
this site has no trackers or ads.
</p>
<p>
you can reach us for feedback and support with the discord and email buttons below.
</p>
<p>
the access code grep842 is currently active.
</p>
<button
class="login-btn"
onClick={() => document.location.assign('https://discord.gg/YJJgurM')}>
Discord
</button>
<button
class="login-btn"
onClick={() => navRegister()}>
Register
</button>
</div>
);
}
module.exports = addState(Register);

View File

@ -0,0 +1,91 @@
// eslint-disable-next-line
const preact = require('preact');
const { Component } = require('preact')
const { connect } = require('preact-redux');
const linkState = require('linkstate').default;
const { postData, errorToast, infoToast } = require('../utils');
const addState = connect(
(state) => {
const {
ws
} = state;
function submitRecover(email) {
postData('/account/recover', { email })
.then(res => res.json())
.then(data => {
if (data.error) return errorToast(data.error);
infoToast(data.message);
})
.catch(error => errorToast(error));
}
return {
submitRecover,
}
},
);
const EMAIL_SUBJECT = name => `
account support: ${name || 'CHANGEME'}
`;
const EMAIL_BODY = `
---
include some details regarding your account. ie.
- account name
- construct names
---
`;
function Register(args) {
const {
submitRecover,
} = args;
const { email } = this.state;
const buttonSubmit = (event) => {
event.preventDefault();
submitRecover(email);
// this.setState({ email: '' });
};
const buttonDisabled = () => {
return !email;
};
const supportLink = encodeURI(`mailto:humans@mnml.gg?subject=${EMAIL_SUBJECT(email)}&body=${EMAIL_BODY}`);
return (
<div class="login">
<p>
send a recovery email to your account's confirmed email address.
</p>
<p>
if you have not set and confirmed an email address for your account
please contact support.
</p>
<label for="username">Account Email</label>
<input
class="login-input"
type="email"
placeholder="player@mnml.gg"
value={email}
onInput={linkState(this, 'email')}
/>
<button
class="login-btn"
disabled={buttonDisabled()}
onClick={buttonSubmit}> Send Recovery Email
</button>
<button>
<a href={supportLink}> support</a>
</button>
</div>
);
}
module.exports = addState(Register);

View File

@ -0,0 +1,61 @@
// eslint-disable-next-line
const preact = require('preact');
const Login = require('./welcome.login');
const Register = require('./welcome.register');
const Help = require('./welcome.help');
const About = require('./welcome.about');
function Welcome() {
const page = this.state.page || 'login';
const navRegister = () => this.setState({ page: 'register' });
const pageEl = () => {
if (page === 'login') return <Login />;
if (page === 'register') return <Register />;
if (page === 'about') return <About navRegister={navRegister} />;
if (page === 'help') return <Help />;
return false;
};
return (
<main class="welcome">
<h1>mnml.gg</h1>
<div class="login">
<div>mnml is an abstract turn based strategy game</div>
<div>free to play</div>
<div>no email required</div>
<div>glhf</div>
</div>
<div class="options">
<button
class={`login-btn ${page === 'login' ? 'highlight' : ''}`}
disabled={page === 'login'}
onClick={() => this.setState({ page: 'login' })}>
Login
</button>
<button
class={`login-btn ${page === 'register' ? 'highlight' : ''}`}
disabled={page === 'register'}
onClick={() => this.setState({ page: 'register' })}>
Register
</button>
<button
class={`login-btn ${page === 'about' ? 'highlight' : ''}`}
disabled={page === 'about'}
onClick={() => this.setState({ page: 'about' })}>
About
</button>
<button
class={`login-btn ${page === 'help' ? 'highlight' : ''}`}
disabled={page === 'help'}
onClick={() => this.setState({ page: 'help' })}>
Help
</button>
</div>
{pageEl()}
</main>
);
}
module.exports = Welcome;

View File

@ -0,0 +1,80 @@
// eslint-disable-next-line
const preact = require('preact');
const { Component } = require('preact')
const { connect } = require('preact-redux');
const linkState = require('linkstate').default;
const { postData, errorToast } = require('../utils');
const addState = connect(
(state) => {
const {
ws
} = state;
function submitLogin(name, password) {
postData('/account/login', { name, password })
.then(res => res.json())
.then(data => {
if (data.error) return errorToast(data.error);
console.log(data.message);
ws.connect();
})
.catch(error => errorToast(error));
}
return {
submitLogin,
}
},
);
function Login(args) {
const {
submitLogin,
} = args;
const { password, name } = this.state;
const loginSubmit = (event) => {
event.preventDefault();
submitLogin(name, password);
this.setState({ name: '', password: '' });
};
const loginDisabled = () => {
return !(password && name);
};
return (
<div class="login">
<label for="username">Username</label>
<input
class="login-input"
type="email"
placeholder="username"
tabIndex={1}
value={name}
onInput={linkState(this, 'name')}
/>
<label for="password">Password</label>
<input
class="login-input"
type="password"
placeholder="password"
tabIndex={2}
value={password}
onInput={linkState(this, 'password')}
/>
<button
class="login-btn"
tabIndex={4}
disabled={loginDisabled()}
onClick={loginSubmit}>
Login
</button>
</div>
);
}
module.exports = addState(Login);

View File

@ -0,0 +1,96 @@
// eslint-disable-next-line
const preact = require('preact');
const { Component } = require('preact')
const { connect } = require('preact-redux');
const linkState = require('linkstate').default;
const { postData, errorToast, infoToast } = require('../utils');
const addState = connect(
(state) => {
const {
ws
} = state;
function submitRegister(name, password, code) {
postData('/account/register', { name, password, code })
.then(res => res.json())
.then(data => {
if (data.error) return errorToast(data.error);
infoToast(data.message);
ws.connect();
})
.catch(error => errorToast(error));
}
return {
submitRegister,
}
},
);
function Register(args) {
const {
submitRegister,
} = args;
const { password, confirm, name, code } = this.state;
const registerSubmit = (event) => {
event.preventDefault();
submitRegister(name, password, code);
// this.setState({ name: '', password: '', confirm: '', code: ''});
}
const registerConfirm = () =>
password === confirm;
const registerDisabled = () => {
return !(registerConfirm() && password && name && code);
}
return (
<div class="login">
<label for="username">Username</label>
<input
class="login-input"
type="email"
placeholder="username"
value={this.state.name}
onInput={linkState(this, 'name')}
/>
<label for="password">Password - min 12 chars</label>
<input
class="login-input"
type="password"
placeholder="password"
value={this.state.password}
onInput={linkState(this, 'password')}
/>
<label for="confirm">Confirm Password</label>
<input
class={`${registerConfirm() ? '' : 'red'} login-input`}
type="password"
placeholder="confirm"
value={this.state.confirm}
onInput={linkState(this, 'confirm')}
/>
<label for="code">Access Code</label>
<input
class="login-input"
type="text"
placeholder="code"
value={this.state.code}
onInput={linkState(this, 'code')}
/>
<button
class="login-btn"
disabled={registerDisabled()}
onClick={registerSubmit}>
Register
</button>
</div>
);
}
module.exports = addState(Register);

View File

@ -9,6 +9,7 @@ exports.up = async knex => {
table.string('token', 64)
.notNullable()
.index();
table.timestamp('token_expiry').notNullable();
table.bigInteger('balance')

View File

@ -42,10 +42,13 @@ pub enum Mail {
fn recover(email: &String, name: &String, token: &String) -> SendableEmail {
let body = format!("{:},
the link below will recover your account.
please change your password immediately in the account page
please change your password immediately in the account page.
this link will expire in 48 hours or once used.
http://mnml.gg/api/account/recover?recover_token={:}
glhf", name, token);
glhf
--mnml", name, token);
Email::builder()
.from("machines@mnml.gg")
@ -62,7 +65,8 @@ fn confirm(email: &String, name: &String, token: &String) -> SendableEmail {
please click the link below to confirm your email
http://mnml.gg/api/account/email/confirm?confirm_token={:}
glhf", name, token);
glhf
--mnml", name, token);
Email::builder()
.from("machines@mnml.gg")