Wrote a badge list page

This commit is contained in:
2019-06-08 17:10:33 +10:00
parent 9a42ef54f3
commit 562fae3871
12 changed files with 152 additions and 16 deletions
+1 -1
View File
@@ -97,7 +97,7 @@ New equipment becomes accessible as soon as you train a new scientist, and purch
<div class="break" /> <div class="break" />
--Coming Soon-- Badges are bling - vanity items that appear next to your name on the game ladder and profile. Some are easy to unlock, others require specific situations. Others still are exclusives, and no longer available. You can see a full list of badges on the [badges list page](/badges/list).
<div class="break" /> <div class="break" />
+2
View File
@@ -1,2 +1,4 @@
* No usernames that are outright hurtful, attack any group or individual, or deliberately cross the line. * No usernames that are outright hurtful, attack any group or individual, or deliberately cross the line.
* Using automated user accounts, or "botting", is not allowed and will result in an immediate ban. * Using automated user accounts, or "botting", is not allowed and will result in an immediate ban.
* One account per player.
* Don't make me add more rules.
+3 -3
View File
@@ -1,8 +1,6 @@
Major Major
--- ---
* Implement badges.
* Write the instructions for badges.
* Implement countdown timers for combat and training. * Implement countdown timers for combat and training.
* Implement referral links. * Implement referral links.
* Implement admin panel (write posts without having to commit). * Implement admin panel (write posts without having to commit).
@@ -30,6 +28,7 @@ Patch
* Ezekiel-powered discord role for kingdom battles players. * Ezekiel-powered discord role for kingdom battles players.
* Refactor callback-hell (yes, it is that bad). * Refactor callback-hell (yes, it is that bad).
* Treasure? * Treasure?
* Add a link home to the verification message.
Potential And Confirmed Bugs Potential And Confirmed Bugs
--- ---
@@ -45,6 +44,7 @@ Wishlist
* Implement nations (player alliances) (sending items/gold). * Implement nations (player alliances) (sending items/gold).
* In-game chat. * In-game chat.
* Structures / shields. * Structures / shields.
* Sharding.
Event Ideas Event Ideas
--- ---
@@ -54,7 +54,7 @@ Event Ideas
Badge Ideas Badge Ideas
--- ---
* alpha tester * ~~alpha tester~~
* capture the flag * capture the flag
* king of the hill * king of the hill
* gold horde * gold horde
+1
View File
@@ -8,3 +8,4 @@ There are five badges so far, but I need to actually code in the triggers for th
Sadly, I don't think my fancy rainbox text will work with the badge component hogging it's spot. If I want rainbow usernames, I'll need to code a hybrid component... Sadly, I don't think my fancy rainbox text will work with the badge component hogging it's spot. If I want rainbow usernames, I'll need to code a hybrid component...
Edit: I've added a [badge list page](/badges/list) for easy perusal.
+6 -6
View File
@@ -3,30 +3,30 @@
"filename": "alpha_tester.png", "filename": "alpha_tester.png",
"description": "Awarded to everyone who joined before or on the 7th of June, 2019 (AEST).", "description": "Awarded to everyone who joined before or on the 7th of June, 2019 (AEST).",
"visible": true, "visible": true,
"earnable": false "unlockable": false
}, },
"Capture The Flag": { "Capture The Flag": {
"filename": "capture_the_flag.png", "filename": "capture_the_flag.png",
"description": "This badge is stolen by successful attacks.", "description": "This badge is stolen by successful attacks. It is automatically set as your active badge, and you can't change it until it is lost; it also sets your name to yellow, so everyone knows you have it. Only one exists.",
"visible": true, "visible": true,
"earnable": true "unlockable": null
}, },
"Combat Master": { "Combat Master": {
"filename": "combat_master.png", "filename": "combat_master.png",
"description": "You have successfully attacked 100 times.", "description": "You have successfully attacked 100 times.",
"visible": true, "visible": true,
"earnable": true "unlockable": null
}, },
"Gold Horde": { "Gold Horde": {
"filename": "gold_horde.png", "filename": "gold_horde.png",
"description": "You purchased this badge for 500 gold.", "description": "You purchased this badge for 500 gold.",
"visible": true, "visible": true,
"earnable": true "unlockable": null
}, },
"King Of The Hill": { "King Of The Hill": {
"filename": "king_of_the_hill.png", "filename": "king_of_the_hill.png",
"description": "You held your position at the top of the game ladder for a whole day.", "description": "You held your position at the top of the game ladder for a whole day.",
"visible": true, "visible": true,
"earnable": true "unlockable": null
} }
} }
+1
View File
@@ -71,6 +71,7 @@ export default class App extends React.Component {
<LazyRoute path='/ladder' component={() => import('./pages/ladder.jsx')} /> <LazyRoute path='/ladder' component={() => import('./pages/ladder.jsx')} />
<LazyRoute path='/combatlog' component={() => import('./pages/combat_log.jsx')} /> <LazyRoute path='/combatlog' component={() => import('./pages/combat_log.jsx')} />
<LazyRoute path='/spyinglog' component={() => import('./pages/spying_log.jsx')} /> <LazyRoute path='/spyinglog' component={() => import('./pages/spying_log.jsx')} />
<LazyRoute path='/badges/list' component={() => import('./pages/badge_list.jsx')} />
<LazyRoute path='/badges' component={() => import('./pages/badge_select.jsx')} /> <LazyRoute path='/badges' component={() => import('./pages/badge_select.jsx')} />
<LazyRoute path='/tasklist' component={() => import('./pages/task_list.jsx')} /> <LazyRoute path='/tasklist' component={() => import('./pages/task_list.jsx')} />
+50
View File
@@ -0,0 +1,50 @@
import React from 'react';
//panels
import CommonLinks from '../panels/common_links.jsx';
import BadgeListPanel from '../panels/badge_list.jsx';
class BadgeList extends React.Component {
constructor(props) {
super(props);
this.state = {
warning: '', //TODO: unified warning?
fetch: null
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
this.state.fetch();
}
render() {
let warningStyle = {
display: this.state.warning.length > 0 ? 'flex' : 'none'
};
return (
<div className='page'>
<div className='sidePanelPage'>
<div className='sidePanel'>
<CommonLinks />
</div>
<div className='mainPanel'>
<div className='warning' style={warningStyle}>
<p>{this.state.warning}</p>
</div>
<h1 className='centered'>Badges</h1>
<BadgeListPanel setWarning={this.setWarning.bind(this)} getFetch={ (fn) => this.setState({ fetch: fn }) } />
</div>
</div>
</div>
);
}
setWarning(s) {
this.setState({ warning: s });
}
};
export default BadgeList;
+3 -2
View File
@@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { withRouter, Link } from 'react-router-dom';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
//panels //panels
@@ -42,7 +43,7 @@ class BadgeSelect extends React.Component {
</div> </div>
<h1 className='centered'>Badge Select</h1> <h1 className='centered'>Badge Select</h1>
<p className='centered'>Click on your favourite badge!</p> <p className='centered'>Click on your favourite badge! <Link to='/badges/list'>Full list here</Link>.</p>
<BadgeSelectPanel setWarning={this.setWarning.bind(this)} getFetch={ (fn) => this.setState({ fetch: fn }) } /> <BadgeSelectPanel setWarning={this.setWarning.bind(this)} getFetch={ (fn) => this.setState({ fetch: fn }) } />
</div> </div>
</div> </div>
@@ -70,4 +71,4 @@ const mapDispatchToProps = (dispatch) => {
BadgeSelect = connect(mapStoreToProps, mapDispatchToProps)(BadgeSelect); BadgeSelect = connect(mapStoreToProps, mapDispatchToProps)(BadgeSelect);
export default BadgeSelect; export default withRouter(BadgeSelect);
+1 -1
View File
@@ -17,7 +17,7 @@ class Badge extends React.Component {
let realSize = typeof(this.props.size) === 'number' ? this.props.number : this.parseSize(this.props.size); let realSize = typeof(this.props.size) === 'number' ? this.props.number : this.parseSize(this.props.size);
return ( return (
<img {...this.props} src={`/img/badges/${this.props.filename}`} alt={this.props.name} width={realSize} height={realSize} /> <img {...this.props} src={`/img/badges/${this.props.filename}`} alt={this.props.name} width={realSize} height={realSize} style={{ minWidth: realSize, minHeight: realSize }} />
); );
} }
+81
View File
@@ -0,0 +1,81 @@
import React from 'react';
import PropTypes from 'prop-types';
import Badge from './badge.jsx';
class BadgeList extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {}
};
if (props.getFetch) {
props.getFetch(() => this.sendRequest('/badgeslistrequest'));
}
}
render() {
if (!this.state.data.statistics) {
return (
<p className='panel'>Loading badges...</p>
);
}
return (
<div className='panel table'>
{Object.keys(this.state.data.statistics).map((name) =>
<div key={name}>
<div className={'panel row'} style={{padding: 10}}>
<div className={'col centered'} style={{ minWidth: 110 }}>
<Badge name={name} filename={this.state.data.statistics[name].filename} />
</div>
<div className={'col'} style={{flex: 4, display: 'flex', flexDirection: 'column', justifyContent: 'center'}}>
<h2>{name}</h2>
<p>{this.state.data.statistics[name].description}</p>
<p>Unlockable: {this.state.data.statistics[name].unlockable ? <span style={{color: 'lightgreen'}}>Yes</span> : this.state.data.statistics[name].unlockable === null ? <span style={{color: 'yellow'}}>Coding Incomplete</span> : <span style={{color: 'red'}}>No</span>}</p>
</div>
</div>
<div className='row'>
<hr className='col mobile show' />
</div>
</div>
)}
</div>
);
}
//gameplay functions
sendRequest(url, args = {}) { //send a unified request, using my credentials
//build the XHR
let xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
let json = JSON.parse(xhr.responseText);
//on success
this.setState({ data: Object.assign({}, this.state.data, json) });
}
else if (xhr.status === 400 && this.props.setWarning) {
this.props.setWarning(xhr.responseText);
}
}
};
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
xhr.send(JSON.stringify({
...args
}));
}
};
BadgeList.propTypes = {
setWarning: PropTypes.func,
getFetch: PropTypes.func
};
export default BadgeList;
+1 -1
View File
@@ -50,7 +50,7 @@ class BadgeSelect extends React.Component {
<hr className='col mobile show' /> <hr className='col mobile show' />
</div> </div>
</div> </div>
)} ).reverse()}
</div> </div>
); );
} }
+2 -2
View File
@@ -22,9 +22,9 @@ class BadgeText extends React.Component {
let style = this.props.centered ? centerStyle : leftStyle; let style = this.props.centered ? centerStyle : leftStyle;
return ( return (
<div {...this.props} style={{...style, paddingBottom: '0.5em'}}> <div className={this.props.className} style={{...style, paddingBottom: '0.5em'}}>
<Badge name={this.props.name} filename={this.props.filename} size={this.props.size} /> <Badge name={this.props.name} filename={this.props.filename} size={this.props.size} />
<p style={{paddingBottom: 0}}>{this.props.children}</p> <p style={{paddingBottom: 0, ...this.props.style}}>{this.props.children}</p>
</div> </div>
); );
} }