Wrote a badge list page
This commit is contained in:
@@ -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" />
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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')} />
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
@@ -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 }} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user